wxauto 微信 PC 自动化完整实战:从零搭建消息机器人背后的 3 大核心机制
wxauto 微信 PC 自动化完整实战从零搭建消息机器人背后的 3 大核心机制【免费下载链接】wxautoWindows版本微信客户端非网页版自动化可实现简单的发送、接收微信消息简单微信机器人项目地址: https://gitcode.com/gh_mirrors/wx/wxauto从一次人肉客服说起凌晨两点运营同学还在对着微信窗口一条条复制粘贴通知。你顺手写了个脚本想用requests调一下微信的接口——然后发现 PC 版微信根本没有公开的 HTTP API想抓包模拟协议又担心封号和逆向复杂度。这时候最务实的路径只剩一条直接操作桌面 UI。而wxauto项目路径wxauto/做的就是这件事——它基于 Windows 自带的 UIAutomation 技术让你用十几行 Python 就能驱动 PC 版微信3.9.X自动收发消息、发文件、处理好友申请把人肉客服变成定时机器人。这篇文章不打算罗列 API 清单而是沿着一个核心问题展开不碰协议、不改客户端的前提下怎么让代码像人一样操作微信顺着这个问题你会看到 wxauto 的 3 大核心机制以及一套可以直接落地的实战代码。技术选型为什么是 UIAutomation而不是其他三条路在决定用什么方式控制微信时可选方案大致有四类每一类的代价都不同方案实现成本封号风险平台依赖典型问题UIAutomation 控件操作低低模拟人类操作仅 Windows控件定位受版本影响抓包 协议模拟极高高跨平台协议频繁变更、易触发风控图像识别OpenCV中中跨平台慢、受分辨率和主题影响大内存 Hook / DLL 注入极高极高仅 Windows客户端更新即失效wxauto 选了最笨也最稳的一条UIAutomation。它不向微信发送任何伪造的数据包只是模拟人的操作——点击、输入、滚动、粘贴。微信的视角里你的脚本和一个真实用户没有区别这正是它风险低的根本原因。代价也很明确代码必须知道控件长什么样而微信一升级控件树可能就变了。这也是 wxauto 在源码里标注微信 3.9.X版本范围的原因。机制一窗口三区划分把 UI 树变成地图启动一个 wxauto 实例时WeChat.__init__里发生的第一件事就是定位主窗口并解析它的布局。源码中的注释画了一张简图wxauto/wxauto.py# _______________ # |■|———| -□×| # | |———| | # |A| B | C | --- 微信窗口布局简图示意 # | |———|———————| # ||———| | # ———————————————定位顺序是按类名找主窗口 → 跳过无类名的中间容器 → 取到三个子区域# 这段代码解决如何把微信窗口拆解成可编程的区域的问题 self.UiaAPI uia.WindowControl(ClassNameWeChatMainWndForPC, searchDepth1) MainControl1 [i for i in self.UiaAPI.GetChildren() if not i.ClassName][0] MainControl2 MainControl1.GetFirstChildControl() # 三个布局导航栏(A)、聊天列表(B)、聊天框(C) self.NavigationBox, self.SessionBox, self.ChatBox MainControl2.GetChildren()之后的所有操作都在这张地图上展开属性命名也很有规律A_xxx导航栏里的按钮如A_ChatIcon聊天、A_ContactsIcon通讯录B_xxx会话列表控件如B_Search搜索框C_xxx聊天区域控件如C_MsgList消息列表为什么这么设计因为 UIAutomation 的控件查找是整棵树遍历每次都从根节点开始搜代价很高。先一次性把三个区域缓存成成员变量后续所有操作就限定在局部子树里既缩短了查找路径也让代码读起来像一张控件地图——这是典型的以空间换时间 语义化命名的取舍。机制二消息识别——用高度指纹分类用 RuntimeId 去重拿到聊天窗口后最难的不是点按钮而是读懂屏幕上的一条条消息哪些是系统提示、哪些是时间戳、哪些是好友发的、哪些是自己发的。wxauto 的做法非常有意思先用控件高度做指纹再用 RuntimeId 做身份证。高度指纹一条消息是什么类型量一下就知道源码里维护了一张高度常量表wxauto/elements.pyclass WxParam: SYS_TEXT_HEIGHT 33 # 系统消息 TIME_TEXT_HEIGHT 34 # 时间标签 RECALL_TEXT_HEIGHT 45 # 撤回提示 CHAT_TEXT_HEIGHT 52 # 普通聊天文本 CHAT_IMG_HEIGHT 117 # 图片消息_split方法拿到一个消息控件后先量它的BoundingRectangle.height()命中哪个档位就归哪类非固定高度比如 52px 的普通消息再通过按钮控件在左右两半区的位置判断是好友发的还是自己发的# 这段代码解决如何不解析协议就判断消息类型与发送方向的问题 if MsgItem.BoundingRectangle.height() WxParam.SYS_TEXT_HEIGHT: Msg [SYS, MsgItemName, .join([str(i) for i in MsgItem.GetRuntimeId()])] elif MsgItem.BoundingRectangle.height() WxParam.TIME_TEXT_HEIGHT: Msg [Time, MsgItemName, ...] else: # 通过头像按钮的水平位置判断消息归属 mid (winrect.left winrect.right) / 2 if User.BoundingRectangle.left mid: name (User.Name, MsgItem.TextControl().Name) # 好友消息 else: name Self # 自己发送的消息这个量高度定类型的设计初看很 hack实际非常聪明UIAutomation 拿不到微信内部的消息结构但拿得到每个控件的几何信息而几何信息恰好与消息类型强相关。不过它也是脆弱的——微信改版导致高度变化时这套指纹就要跟着调这正是 wxauto 强调版本匹配的原因。RuntimeId消息的指纹身份证收消息时最怕重复处理。wxauto 用GetRuntimeId()UIA 为控件生成的进程内唯一 ID拼成字符串作为消息 ID存进usedmsgid列表新消息就是当前列表里不在usedmsgid中的那些# 这段代码解决如何判断哪些消息是新增的问题 MsgItems self.C_MsgList.GetChildren() NewMsgItems [i for i in MsgItems if .join([str(i) for i in i.GetRuntimeId()]) not in self.usedmsgid]每次轮询结束时用全量 ID 刷新usedmsgid既避免漏收也避免重收——这是整个消息监听机制去重的地基。统一的消息对象类型分派ParseMessage是一个小型工厂把[SYS|Time|Recall|Self|(name, remark)]的第一项映射到对应的消息类# 这段代码解决如何把解析结果转成统一的、可扩展的消息对象问题 message_types { SYS: SysMessage, Time: TimeMessage, Recall: RecallMessage, Self: SelfMessage, } def ParseMessage(data, control, wx): return message_types.get(data[0], FriendMessage)(data, control, wx)每个消息对象都暴露sender、content、id属性FriendMessage还带quote()引用回复和forward()转发方法——二次开发时你只需要isinstance(msg, FriendMessage)就能分支处理。机制三发送消息——剪贴板是中间人发送消息时wxauto 并没有走给输入框 SetValue这条路而是走了一条更接近人类操作的链路SetClipboardText(msg) → CtrlV 粘贴 → 校验输入框 ValuePattern 非空 → Enter 发送关键代码在WeChat.SendMsgwxauto/wxauto.py里# 这段代码解决如何稳定地把长文本/特殊内容送进微信输入框的问题 if msg: t0 time.time() while True: if time.time() - t0 10: raise TimeoutError(f发送消息超时 -- {editbox.Name} - {msg}) SetClipboardText(msg) # 1. 文本写入剪贴板 editbox.SendKeys({Ctrl}v) # 2. 模拟粘贴 if editbox.GetValuePattern().Value: # 3. 确认输入框真的有内容 break # 4. 失败则重试10 秒超时兜底 editbox.SendKeys({Enter}) # 5. 回车发送为什么用剪贴板而不是直接设置文本两个原因一是微信输入框是自绘控件SendKeys直接打长文本容易丢失字符粘贴更接近真实用户输入二是像文件、图片这类富内容只能通过把文件路径写入剪贴板的CF_HDROP格式再粘贴来实现。SendFiles用的就是同一套路utils.py的SetClipboardFiles。发送后的校验循环确认ValuePattern().Value非空才继续和超时兜底是 wxauto 稳定性的两个细节宁可重试不静默失败。机制四红色像素检测——不依赖控件也能感知新消息主窗口的聊天图标上出现红点表示有新消息。但这个红点未必是 UIAutomation 能拿到的标准控件。wxauto 的解法是直接抓像素utils.py# 这段代码解决如何检测 UI 树里看不到的红色未读标记问题 def IsRedPixel(uicontrol): rect uicontrol.BoundingRectangle bbox (rect.left, rect.top, rect.right, rect.bottom) img ImageGrab.grab(bboxbbox, all_screensTrue) return any(p[0] p[1] and p[0] p[2] for p in img.getdata())红色的判定标准是R G 且 R B然后CheckNewMessage()用它决定是否进入切到聊天列表 → 找出有新消息的会话 → 逐个打开收取的流程。这是控件不可达时用图像兜底的典型案例——机制组合而不是单点依赖正是这类自动化框架能活下去的关键。实战10 行代码跑通收一发一把上面的机制串起来一个最小可用机器人长这样。先安装并克隆仓库https://gitcode.com/gh_mirrors/wx/wxauto确保微信已登录且版本为 3.9.Xfrom wxauto import WeChat wx WeChat() # 初始化解析窗口三区打印当前登录昵称 wx.SendMsg(你好我是自动回复机器人, who文件传输助手) # 发送消息 msgs wx.GetAllMessage() # 读取当前窗口消息 for msg in msgs: print(msg.type, msg.sender, msg.content) # 如 friend 张三 晚上一起吃饭吗监听并自动回复这是docs/README.md快速开始之外最常见的场景import time from wxauto import WeChat wx WeChat() wx.AddListenChat(who张三) # 为张三单独开一个监听会话窗口 while True: msgs wx.GetListenMessage(who张三) # 只取张三的新消息 for chat, msg_list in msgs.items() if isinstance(msgs, dict) else [(张三, msgs)]: for msg in msg_list: if msg.type friend: # 只回复好友消息忽略系统/时间消息 print(f收到 {msg.sender}: {msg.content}) msg.quote(收到已自动回复) # 引用回复更像真人 time.sleep(1) # 轮询间隔给 UI 一点喘息如果你只想统一收一遍所有新消息可以换成wx.GetAllNewMessage(max_round10)——它会自动遍历所有有新消息的会话并聚合返回一个字典。再给两个高频场景的代码都直接对应源码中的真实 API自动保存聊天图片并处理新好友申请wxauto/elements.py的WeChatImage与NewFriendsElementfrom wxauto import WeChat wx WeChat() wx.GetAllMessage(savepicTrue) # 遇到图片消息自动下载到 wxauto文件/ 目录 newfriends wx.GetNewFriends() # 拉取待处理的好友申请 for friend in newfriends: friend.Accept(remark自动通过, tags[客户, 来源:机器人]) # 接受并打标签批量发文件SendFiles支持字符串或列表走剪贴板粘贴wx.SendFiles([rD:/report/日报20260816.pdf, rD:/report/周报.pdf], who项目群)稳定性的四个细节性能不靠快靠确认这类 UI 自动化最怕的不是慢而是**你以为成功了其实没有**。wxauto 在稳定性上做了四件事值得你在自己的自动化项目里照抄写入确认粘贴文本/文件后轮询GetValuePattern().Value内容进框才发10 秒超时抛TimeoutError。滚动确认LoadMoreMessage()用滚动前控件的 top 坐标是否变化判断是否滚到底而不是盲目滚 N 次。缓存去重usedmsgid在全局主窗口和会话级ChatWnd实例各维护一份从机制上杜绝重复处理。窗口级容错ChatWith找不到完全匹配时走搜索框兜底仍找不到则_refresh()CtrlAltW重显窗口后返回False把异常转成可判断的返回值。关于性能可以给你一组量级参考初始化一次窗口解析约 1~2 秒单条文本发送在 200~500ms 量级含剪贴板操作与校验图片/文件发送约 1~2 秒。这个量级下轮询间隔 0.5~1 秒 批量操作间加 0.3 秒是性价比最高的调优组合再激进就会开始触发微信的交互限流。踩坑清单这 5 个坑 90% 的人都会踩微信版本必须匹配。源码中VERSION 3.9.11.17_checkversion()通过进程路径读取 exe 版本号做校验。用 4.0 新版微信控件树大变A_xxx/C_xxx定位会全部失效——先锁版本再谈自动化。窗口别最小化到托盘。_show()里用win32gui.ShowWindowSetWindowPos把窗口拉到前台但如果微信退出到托盘主窗口可能根本没创建初始化就会失败。保证微信以窗口形式常驻。GetFriendDetails很慢别全量跑。源码注释明确写了约 0.5~1 秒一个好友并且遇到已离职的企业微信好友可能导致微信卡死微信客户端 BUG。全量好友详情按需取测试时务必传n限制数量。who参数要完整匹配优先。ChatWith对不完全匹配会走搜索框选第一条同名联系人会选错人。发送前先GetSessionList()拿到真实名字优先用备注名。不要在循环里高频操作剪贴板。SetClipboardText/SetClipboardFiles会与其他程序抢剪贴板批量场景下加入节流比如每两条消息间隔 0.5 秒既稳又不容易触发风控。二次开发三个可扩展的切入点wxauto 的源码结构清晰做扩展有天然的落点消息层wxauto/elements.pyParseMessage的message_types字典就是一张类型注册表你可以仿照SysMessage/FriendMessage新增自定义消息类或给FriendMessage加自己的方法如接 LLM 生成回复。窗口层wxauto/wxauto.pyWeChat的子类可以直接挂业务逻辑。比如一个关键词自动应答器核心就是重写监听循环用msg.content做规则匹配。工具层wxauto/utils.pySetClipboardFiles、IsRedPixel、RollIntoView都是与微信无关的通用函数可以原样复用到其他桌面应用自动化里。一个真实的最小扩展示例——把消息接给大模型from wxauto import WeChat wx WeChat() wx.AddListenChat(who客服群) def ai_reply(text: str) - str: # 这里接入你的 LLM 接口比如本地 Ollama / 云端 API return f[AI] 已收到你的问题{text[:20]}… while True: for chat, msgs in wx.GetListenMessage().items(): for msg in msgs: if msg.type friend: wx.SendMsg(ai_reply(msg.content), whomsg.sender) time.sleep(2)注意GetListenMessage()的返回值在源码里是dictkey 为ChatWnd对象遍历时按字典处理即可。局限与展望它适合什么不适合什么客观地说wxauto 有清晰的边界能做不建议做个人自动化、小流量通知、测试环境机器人大规模营销群发、24x7 无人值守生产Windows 微信 3.9.X 桌面环境跨平台macOS/Linux 无 UIAutomation模拟真人操作的低风险任务任何触碰账号安全的灰产操作项目 README 里也明确声明仅用于对 UIAutomation 技术的交流学习。把它定位成你自己的效率工具而不是商用机器人基础设施是使用它的正确姿势。下一步动手三步走先跑通最小闭环登录微信 3.9.X →pip install wxauto→ 复制上面的收发消息代码改掉who为你自己的会话名。再深入源码读wxauto/wxauto.py的WeChat.__init__窗口三区和SendMsg剪贴板链路你会对本篇文章讲的机制有具象认知完整接口速查在docs/目录docs/README.md快速开始、docs/example.md场景示例。最后写你的业务从每天定时给运营群发日报这类小需求开始跑通后再考虑关键词应答、好友申请自动处理等进阶玩法。微信的每一次改版都是对这套方案的重新考验但控件定位 像素兜底 剪贴板注入这套组合拳的思路值得你在任何桌面自动化项目里复用。现在打开微信跑起你的第一行wx WeChat()吧。【免费下载链接】wxautoWindows版本微信客户端非网页版自动化可实现简单的发送、接收微信消息简单微信机器人项目地址: https://gitcode.com/gh_mirrors/wx/wxauto创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考