""" 日报自动化填写脚本 依赖安装: 1. 安装Python依赖包: pip install playwright pip install psutil pip install asyncio 2. 安装Playwright浏览器: playwright install chromium 注意事项: 1. 确保Chrome浏览器已安装 2. 脚本使用Chrome用户配置文件,路径为:C:/Users/zhens/AppData/Local/Google/Chrome/User Data 3. 运行前请确保没有其他Chrome进程在运行 4. 脚本会自动关闭所有Chrome进程,请确保没有重要工作未保存 5. 如果修改了Chrome用户配置路径,需要相应修改代码中的user_data_dir变量 6. 脚本运行时会打开Chrome浏览器窗口,请勿手动操作浏览器 7. 如果遇到网络问题,可以适当增加等待时间(asyncio.sleep的值) 8. 如果提交失败,可以检查网络连接或适当增加等待时间 """ import asyncio import os import psutil import time import tkinter as tk from tkinter import scrolledtext from playwright.async_api import async_playwright def get_user_input(): """通过GUI窗口获取用户输入的日报内容""" root = tk.Tk() root.title("日报填写助手") root.geometry("900x700") # 设置窗口样式 root.configure(bg='#f0f0f0') root.option_add('*Font', '微软雅黑 10') # 设置窗口图标(如果有的话) try: root.iconbitmap('icon.ico') # 如果有图标文件的话 except: pass # 创建主框架 main_frame = tk.Frame(root, bg='#f0f0f0', padx=20, pady=20) main_frame.pack(fill=tk.BOTH, expand=True) # 创建标题 title_label = tk.Label(main_frame, text="日报填写", font=("微软雅黑", 16, "bold"), bg='#f0f0f0', pady=10) title_label.pack() # 创建今日工作总结输入区域 summary_frame = tk.LabelFrame(main_frame, text="今日工作总结", font=("微软雅黑", 12), bg='#f0f0f0', padx=10, pady=5) summary_frame.pack(fill=tk.BOTH, expand=True, pady=10) summary_text = scrolledtext.ScrolledText(summary_frame, width=80, height=8, font=("微软雅黑", 11), wrap=tk.WORD, padx=10, pady=10) summary_text.pack(fill=tk.BOTH, expand=True) # 添加字数统计 summary_count = tk.Label(summary_frame, text="字数:0", font=("微软雅黑", 10), bg='#f0f0f0', anchor='e') summary_count.pack(fill=tk.X, padx=10) # 创建明日工作计划输入区域 plan_frame = tk.LabelFrame(main_frame, text="明日工作计划", font=("微软雅黑", 12), bg='#f0f0f0', padx=10, pady=5) plan_frame.pack(fill=tk.BOTH, expand=True, pady=10) plan_text = scrolledtext.ScrolledText(plan_frame, width=80, height=8, font=("微软雅黑", 11), wrap=tk.WORD, padx=10, pady=10) plan_text.pack(fill=tk.BOTH, expand=True) # 添加字数统计 plan_count = tk.Label(plan_frame, text="字数:0", font=("微软雅黑", 10), bg='#f0f0f0', anchor='e') plan_count.pack(fill=tk.X, padx=10) # 创建底部控制区域 bottom_frame = tk.Frame(main_frame, bg='#f0f0f0', pady=10) bottom_frame.pack(fill=tk.X) # 创建复选框 keep_original = tk.BooleanVar(value=False) check_button = tk.Checkbutton(bottom_frame, text="保留原有内容", variable=keep_original, font=("微软雅黑", 11), bg='#f0f0f0') check_button.pack(side=tk.LEFT, padx=10) # 创建提交按钮 result = {"summary": "", "plan": "", "is_submitted": False, "keep_original": False} def submit(): result["summary"] = summary_text.get("1.0", tk.END).strip() result["plan"] = plan_text.get("1.0", tk.END).strip() result["keep_original"] = keep_original.get() result["is_submitted"] = True root.quit() root.destroy() submit_button = tk.Button(bottom_frame, text="提交", command=submit, font=("微软雅黑", 12, "bold"), bg='#4CAF50', fg='white', width=15, height=2, relief=tk.FLAT) submit_button.pack(side=tk.RIGHT, padx=10) # 添加字数统计更新函数 def update_counts(event=None): summary_count.config(text=f"字数:{len(summary_text.get('1.0', tk.END).strip())}") plan_count.config(text=f"字数:{len(plan_text.get('1.0', tk.END).strip())}") # 绑定字数统计更新 summary_text.bind('', update_counts) plan_text.bind('', update_counts) # 初始更新字数统计 update_counts() # 设置窗口居中 root.update_idletasks() width = root.winfo_width() height = root.winfo_height() x = (root.winfo_screenwidth() // 2) - (width // 2) y = (root.winfo_screenheight() // 2) - (height // 2) root.geometry(f'{width}x{height}+{x}+{y}') root.mainloop() return result["summary"], result["plan"], result["is_submitted"], result["keep_original"] # 执行自动化浏览器操作的协程函数 def close_chrome(): """关闭所有Chrome进程""" for proc in psutil.process_iter(['name']): try: if proc.info['name'] == 'chrome.exe': proc.kill() except (psutil.NoSuchProcess, psutil.AccessDenied): pass # 等待进程完全关闭 time.sleep(2) async def run(playwright): try: # 确保Chrome已关闭 close_chrome() # 使用用户实际的Chrome配置,配置查询chrome://version user_data_dir = r'C:/Users/zhens/AppData/Local/Google/Chrome/User Data' def text_to_div_html(text): """将多行文本转换为
...
格式的HTML""" lines = [line.strip() for line in text.strip().splitlines() if line.strip()] return ''.join(f'
{line}
' for line in lines) # 获取用户输入的日报内容 summary_text, plan_text, is_submitted, keep_original = get_user_input() # 如果用户取消输入,直接退出程序 if not is_submitted: print("用户取消了日报填写,程序退出") return summary_html = text_to_div_html(summary_text) plan_html = text_to_div_html(plan_text) # 使用已有的Chrome配置文件启动浏览器 context = await playwright.chromium.launch_persistent_context( user_data_dir, channel="chrome", headless=False, args=[ '--start-maximized', '--disable-blink-features=AutomationControlled', '--profile-directory=Default', '--no-first-run', '--no-default-browser-check' ], ignore_default_args=['--enable-automation'] ) try: # 创建新页面 page = await context.new_page() # 设置实际的User-Agent await page.set_extra_http_headers({ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36' }) # 访问页面并等待网络空闲 await page.goto('https://doc.weixin.qq.com/forms/j/AFIADwd9AA4AUcA6AbCADgJXbq19fUR0j_base?page=6', wait_until='networkidle') # 等待元素出现并点击 await page.wait_for_selector('div.TitleBarBtn_title__dKAyV:text("填写")', timeout=60000) await page.click('div.TitleBarBtn_title__dKAyV:text("填写")', delay=100) # 等待操作完成,确保页面完全加载 await asyncio.sleep(5) # 查找所有可编辑的输入框 editors = await page.query_selector_all('.maileditor-editorview[contenteditable="true"]') print("找到输入框数量:", len(editors)) # 今日工作总结输入 # 1. 先点击输入框,确保获得焦点 await page.locator('div.question:has-text("今日工作总结") .maileditor-editorview[contenteditable="true"]').click() # 2. 如果不保留原有内容,则清空输入框 if not keep_original: await page.keyboard.press('Control+A') await page.keyboard.press('Delete') # 3. 使用键盘输入方式模拟真实输入 await page.keyboard.type(summary_text) # 4. 等待输入完成,确保内容被正确输入 await asyncio.sleep(2) # 明日工作计划输入 # 1. 先点击输入框,确保获得焦点 await page.locator('div.question:has-text("明日工作计划") .maileditor-editorview[contenteditable="true"]').click() # 2. 如果不保留原有内容,则清空输入框 if not keep_original: await page.keyboard.press('Control+A') await page.keyboard.press('Delete') # 3. 使用键盘输入方式模拟真实输入 await page.keyboard.type(plan_text) # 4. 等待输入完成 await asyncio.sleep(2) # 等待内容保存 # 给系统足够的时间来保存输入的内容 await asyncio.sleep(5) # 点击提交按钮 # 1. 等待提交按钮出现 await page.wait_for_selector('button.FillFooter_confirm__0ClPl', timeout=60000) # 2. 点击提交按钮,添加延迟模拟真实点击 await page.click('button.FillFooter_confirm__0ClPl', delay=100) # 等待提交完成 # 给系统足够的时间来处理提交操作 await asyncio.sleep(5) # 显示提交成功提示 print("日报提交成功!") except Exception as e: print(f"提交过程中发生错误: {str(e)}") raise finally: # 确保浏览器正常关闭 await context.close() except Exception as e: print(f"程序运行过程中发生错误: {str(e)}") raise # 主函数,用于启动 playwright 并调用 run 函数 async def main(): async with async_playwright() as playwright: await run(playwright) # 判断当前环境是否已经有事件循环在运行 if __name__ == "__main__": try: # 尝试获取正在运行的事件循环(某些 IDE/Jupyter 会预先启动) loop = asyncio.get_running_loop() except RuntimeError: loop = None # 如果事件循环存在且正在运行(比如在 Jupyter Notebook 中) if loop and loop.is_running(): print("检测到事件循环正在运行,使用 create_task 启动协程") asyncio.create_task(main()) # 使用 create_task 异步运行 else: # 否则,正常使用 asyncio.run 启动主协程 asyncio.run(main())