wxauto源码解读:wxauto.py中的核心类与方法设计
引言:为什么wxauto.py是微信自动化的核心
在Windows平台的微信客户端自动化领域,wxauto项目提供了一套简洁而强大的解决方案。本文将深入剖析其核心文件wxauto.py的架构设计与实现细节,揭示如何通过UI自动化技术实现对微信客户端的精准控制。通过本文,你将获得:
- 对WeChat类核心架构的深度理解
- 消息处理机制的完整工作流程
- 自动化控制的关键技术实现
- 实用功能的代码级解析
WeChat类架构:微信自动化的基石
类继承关系与核心属性
WeChat类作为整个自动化框架的入口点,继承自WeChatBase基类,实现了对微信主窗口的全面控制。其核心架构如下:
WeChat类初始化时会建立与微信主窗口的连接,并完成三大核心区域的布局解析:
# 三个布局,导航栏(A)、聊天列表(B)、聊天框(C)
# _______________
# |■|———| -□×|
# | |———| |
# |A| B | C | <--- 微信窗口布局简图示意
# | |———|———————|
# |=|———| |
# ———————————————
self.NavigationBox, self.SessionBox, self.ChatBox = MainControl2.GetChildren()
多语言支持机制
为实现国际化支持,WeChat类采用了灵活的语言切换机制:
def __init__(
self,
language: Literal['cn', 'cn_t', 'en'] = 'cn',
debug: bool = False
) -> None:
"""微信UI自动化实例
Args:
language (str, optional): 微信客户端语言版本, 可选: cn简体中文 cn_t繁体中文 en英文, 默认cn, 即简体中文
"""
set_debug(debug)
self.language = language
# ...其他初始化代码
通过_lang()方法实现多语言文本的动态切换:
def _lang(self, text, langtype='MAIN'):
if langtype == 'MAIN':
return MAIN_LANGUAGE[text][self.language]
elif langtype == 'WARNING':
return WARNING[text][self.language]
消息处理机制:从接收 to 响应
消息获取流程
WeChat类实现了完整的消息监听与获取机制,其核心流程如下:
关键实现代码在GetNextNewMessage()方法中:
def GetNextNewMessage(self, savepic=False, savefile=False, savevoice=False, timeout=10):
"""获取下一个新消息"""
msgs_ = self.GetAllMessage()
msgids = [i[-1] for i in msgs_]
if not self.usedmsgid:
self.usedmsgid = msgids
newmsgids = [i for i in msgids if i not in self.usedmsgid]
oldmsgids = [i for i in self.usedmsgid if i in msgids]
# ...消息提取与处理逻辑...
return {session:msgs}
消息类型处理
系统能够识别并处理多种消息类型,包括文本、图片、文件和语音:
def _getmsgs(self, msgitems, savepic=False, savefile=False, savevoice=False):
msgs = []
for MsgItem in msgitems:
if MsgItem.ControlTypeName == 'ListItemControl':
msgs.append(self._split(MsgItem))
# ...特殊消息处理逻辑...
for msg in msgs:
if msg.type not in ('friend', 'self'):
continue
if msg.content.startswith(f"[{self._lang('图片')}]") and savepic:
imgpath = self._download_pic(msg.control)
msg.content = imgpath if imgpath else msg.content
elif msg.content.startswith(f"[{self._lang('文件')}]") and savefile:
filepath = self._download_file(msg.control)
msg.content = filepath if filepath else msg.content
elif msg.content.startswith(f"[{self._lang('语音')}]") and savevoice:
voice_text = self._get_voice_text(msg.control)
msg.content = voice_text if voice_text else msg.content
return msgs
核心功能实现详解
1. 聊天窗口控制
ChatWith()方法实现了精准定位并打开指定聊天窗口的功能,支持通过名称搜索和直接访问两种模式:
def ChatWith(self, who, timeout=2):
'''打开某个聊天框
Args:
who ( str ): 要打开的聊天框好友名; * 最好完整匹配,不完全匹配只会选取搜索框第一个
timeout ( num, optional ): 超时时间,默认2秒
Returns:
chatname ( str ): 匹配值第一个的完整名字
'''
self._show()
sessiondict = self.GetSessionList(True)
if who in list(sessiondict.keys())[:-1]:
self.SessionBox.ListItemControl(RegexName=who).Click(simulateMove=False)
return who
else:
# ...搜索逻辑实现...
2. 消息发送系统
SendMsg()方法支持文本消息发送,并提供@功能:
def SendMsg(self, msg, who=None, clear=True, at=None):
"""发送文本消息
Args:
msg (str): 要发送的文本消息
who (str): 要发送给谁,如果为None,则发送到当前聊天页面。 *最好完整匹配,优先使用备注
clear (bool, optional): 是否清除原本的内容,
at (str|list, optional): 要@的人,可以是一个人或多个人
"""
# ...前置检查逻辑...
if at:
if isinstance(at, str):
at = [at]
for i in at:
editbox.SendKeys('@'+i)
atwnd = self.UiaAPI.PaneControl(ClassName='ChatContactMenu')
if atwnd.Exists(maxSearchSeconds=0.1):
atwnd.SendKeys('{ENTER}')
if msg and not msg.startswith('\n'):
msg = '\n' + msg
# ...消息发送逻辑...
3. 监听功能实现
通过AddListenChat()和GetListenMessage()方法组合,实现对指定聊天的持续监听:
def AddListenChat(self, who, savepic=False, savefile=False, savevoice=False):
"""添加监听对象"""
exists = uia.WindowControl(searchDepth=1, ClassName='ChatWnd', Name=who).Exists(maxSearchSeconds=0.1)
if not exists:
self.ChatWith(who)
self.SessionBox.ListItemControl(RegexName=who).DoubleClick(simulateMove=False)
self.listen[who] = ChatWnd(who, self.language)
self.listen[who].savepic = savepic
self.listen[who].savefile = savefile
self.listen[who].savevoice = savevoice
监听状态通过字典维护,可同时监控多个聊天对象:
def GetListenMessage(self, who=None):
"""获取监听对象的新消息"""
if who and who in self.listen:
chat = self.listen[who]
msg = chat.GetNewMessage(savepic=chat.savepic, savefile=chat.savefile, savevoice=chat.savevoice)
return msg
msgs = {}
for who in self.listen:
chat = self.listen[who]
msg = chat.GetNewMessage(savepic=chat.savepic, savefile=chat.savefile, savevoice=chat.savevoice)
if msg:
msgs[chat] = msg
return msgs
高级功能实现
好友管理功能
GetNewFriends()方法实现了新好友请求的获取与处理:
def GetNewFriends(self):
"""获取新的好友申请列表
Returns:
list: 新的好友申请列表,元素为NewFriendsElement对象,可直接调用Accept方法
"""
self._show()
self.SwitchToContact()
self.SessionBox.ButtonControl(Name='ContactListItem').Click(simulateMove=False)
NewFriendsList = [NewFriendsElement(i, self) for i in self.ChatBox.ListControl(Name='新的朋友').GetChildren()]
AcceptableNewFriendsList = [i for i in NewFriendsList if i.acceptable]
wxlog.debug(f'获取到 {len(AcceptableNewFriendsList)} 条新的好友申请')
return AcceptableNewFriendsList
每个好友请求封装为NewFriendsElement对象,支持直接接受并设置备注和标签:
for friend in newfriends:
remark = f'备注{friend.name}'
friend.Accept(remark=remark, tags=tags) # 接受好友请求,并设置备注和标签
群成员管理
GetGroupMembers()方法实现了群成员列表的获取:
def GetGroupMembers(self):
"""获取当前聊天群成员
Returns:
list: 当前聊天群成员列表
"""
ele = self.ChatBox.PaneControl(searchDepth=7, foundIndex=6).ButtonControl(Name='聊天信息')
try:
uia.SetGlobalSearchTimeout(1)
rect = ele.BoundingRectangle
Click(rect)
except:
return
finally:
uia.SetGlobalSearchTimeout(10)
# ...成员列表提取逻辑...
return members
技术挑战与解决方案
UI自动化的稳定性挑战
微信客户端的UI结构可能随版本变化,wxauto通过多种机制保证兼容性:
- 版本检查机制:在初始化时验证微信版本
- 灵活的控件定位:结合类名和搜索深度的控件查找
- 多语言支持:通过语言包适配不同语言版本的微信
def _checkversion(self):
self.HWND = FindWindow(classname='WeChatMainWndForPC')
wxpath = GetPathByHwnd(self.HWND)
wxversion = GetVersionByPath(wxpath)
if wxversion != self.VERSION:
Warnings.lightred(self._lang('版本不一致', 'WARNING').format(wxversion, self.VERSION), stacklevel=2)
return False
消息识别与提取
针对不同类型的消息,系统采用基于控件高度和内容特征的识别方法:
def _split(self, MsgItem):
uia.SetGlobalSearchTimeout(0)
MsgItemName = MsgItem.Name
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, ''.join([str(i) for i in MsgItem.GetRuntimeId()])]
elif MsgItem.BoundingRectangle.height() == WxParam.RECALL_TEXT_HEIGHT:
if '撤回' in MsgItemName:
Msg = ['Recall', MsgItemName, ''.join([str(i) for i in MsgItem.GetRuntimeId()])]
else:
Msg = ['SYS', MsgItemName, ''.join([str(i) for i in MsgItem.GetRuntimeId()])]
# ...其他消息类型处理...
return ParseMessage(Msg, MsgItem, self)
应用示例:构建简单的微信机器人
基于wxauto.py的核心功能,可以快速构建一个自动回复机器人:
# 机器人实现示例
wx = WeChat()
print(f"当前登录用户: {wx.nickname}")
# 添加监听对象
wx.AddListenChat('文件传输助手')
# 消息处理循环
while True:
messages = wx.GetListenMessage()
if messages:
for chat, msgs in messages.items():
for msg in msgs:
if msg.type == 'friend' or msg.type == 'self':
# 简单的echo回复
wx.SendMsg(f"收到消息: {msg.content}", chat.who)
time.sleep(1)
总结与展望
wxauto.py通过精心设计的类结构和方法实现,为Windows微信客户端提供了强大而灵活的自动化能力。其核心优势在于:
- 完整的窗口控制:通过UIAutomation实现对微信界面的精准控制
- 多类型消息处理:支持文本、图片、文件和语音消息的处理
- 灵活的监听机制:可同时监控多个聊天对象
- 多语言支持:适配不同语言版本的微信客户端
未来可以进一步增强的方向:
- 增加更多消息类型的支持(如表情包、小程序等)
- 优化UI元素识别算法,提高版本兼容性
- 增强异步消息处理能力,提升性能
通过深入理解wxauto.py的设计与实现,开发者可以构建更加复杂和强大的微信自动化工具,满足各种场景下的自动化需求。
要开始使用wxauto项目,请通过以下命令获取代码:
git clone https://gitcode.com/gh_mirrors/wx/wxauto
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



