我的编程空间,编程开发者的网络收藏夹
学习永远不晚

【Python】通过第三方库wxauto自动化操作微信电脑客户端

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

【Python】通过第三方库wxauto自动化操作微信电脑客户端

文章目录

一.简介

wxauto是一个Python第三方库,用于自动化操作微信电脑客户端通过wxauto,我们可以使用Python编写脚本,实现以下功能

  • 获取微信好友列表、群组列表、聊天记录等信息。
  • 在微信中发送文本、图片、语音等信息给好友或群组。
  • 自动回复好友或群组的消息。
  • 自动加入或退出群组。
  • 自动发送文件给好友或群组。
  • 自动发送红包给好友或群组。
  • 其他自定义的自动化操作。

使用wxauto需要先安装其库文件,可以使用pip命令进行安装

pip install wxauto

二.wxauto提供的函数

wxauto目前有WxParam、WxUtils、WeChat三个类:

  • 其中WxParam设置基本参数设置。

1.WxUtils类功能函数:

  • SetClipboard(data, dtype=‘text’) 复制文本信息或图片到剪贴板data : 要复制的内容,str 或 Image 图像;
  • Screenshot(hwnd, to_clipboard=True) 为句柄为hwnd的窗口程序截图;hwnd : 句柄;to_clipboard : 是否复制到剪贴板;
  • SavePic(savepath=None, filename=None) 保存截图;savepath:文件保存位置;filename:文件名字;
  • ControlSize(control) 获取控制窗口大小;
  • ClipboardFormats(unit=0, *units) 获取剪切板格式 ;
  • CopyDict()

2.WeChat类主要函数:

  • GetSessionList(self, reset=False) 获取当前会话列表,更新会话列表
  • Search(self, keyword) 查找微信好友或关键词;keywords: 要查找的关键词,最好完整匹配,不完全匹配只会选取搜索框第一个;
  • ChatWith(self, who, RollTimes=None) 打开某个聊天框;who : 要打开聊天框的好友名,最好完整匹配,不完全匹配只会选取搜索框第一个;RollTimes : 默认向下滚动次数,再进行搜索;
  • SendMsg(self, msg, clear=True) 向当前窗口发送消息;msg : 要发送的消息;
  • SendFiles(self, *filepath, not_exists=‘ignore’) 向当前聊天窗口发送文件;not_exists: 如果未找到指定文件,继续或终止程序;*filepath: 要复制文件的绝对路径;
  • SendClipboard(self) 向当前聊天页面发送剪贴板复制的内容;
  • GetAllMessage(self) 获取当前窗口中加载的所有聊天记录;
  • GetLastMessage(self) 获取当前窗口中最后一条聊天记录
  • LoadMoreMessage(self, n=0.1) 定位到当前聊天页面,并往上滚动鼠标滚轮,加载更多聊天记录到内存发送某个桌面程序的截图,如:微信、记事本;name : 要发送的桌面程序名字;classname : 要发送的桌面程序类别名;
  • SendScreenshot(self, name=None, classname=None) 发送某个桌面程序的截图,如:微信、记事本;name : 要发送的桌面程序名字;classname : 要发送的桌面程序类别名;

三.使用

from wxauto import *# 获取当前微信客户端wx = WeChat()# 获取会话列表wx.GetSessionList()# 输出当前聊天窗口聊天消息msgs = wx.GetAllMessagefor msg in msgs:    print('%s : %s'%(msg[0], msg[1]))## 获取更多聊天记录wx.LoadMoreMessage()msgs = wx.GetAllMessagefor msg in msgs:    print('%s : %s'%(msg[0], msg[1]))# 向某人发送消息(以`文件传输助手`为例)msg = '你好~'who = '文件传输助手'wx.ChatWith(who)  # 打开`文件传输助手`聊天窗口wx.SendMsg(msg)  # 向`文件传输助手`发送消息:你好~## 发送换行消息(最近很多人问换行消息如何发送,新增说明一下)msg = '''你好这是第二行这是第三行这是第四行'''who = '文件传输助手'WxUtils.SetClipboard(msg)    # 将内容复制到剪贴板,类似于Ctrl + Cwx.ChatWith(who)  # 打开`文件传输助手`聊天窗口wx.SendClipboard()   # 发送剪贴板的内容,类似于Ctrl + V# 向某人发送文件(以`文件传输助手`为例,发送三个不同类型文件)file1 = 'D:/test/wxauto.py'file2 = 'D:/test/pic.png'file3 = 'D:/test/files.rar'who = '文件传输助手'wx.ChatWith(who)  # 打开`文件传输助手`聊天窗口wx.SendFiles(file1, file2, file3)  # 向`文件传输助手`发送上述三个文件# 注:为保证发送文件稳定性,首次发送文件可能花费时间较长,后续调用会缩短发送时间# 向某人发送程序截图(以`文件传输助手`为例,发送微信截图)name = '微信'classname = 'WeChatMainWndForPC'wx.ChatWith(who)  # 打开`文件传输助手`聊天窗口wx.SendScreenshot(name, classname)  # 发送微信窗口的截图给文件传输助手注:为保证发送文件稳定性,首次发送文件可能花费时间较长,后续调用会缩短发送时间

四.遇到的问题

由于部分版本的微信可能由于UI界面不同从而无法使用,截至2022-06-10最新版本可用

  • 因此在代码运行的时候,会发现图片无法发送、消息无法发送的报错情况 LookupError: Find Control Timeout(10s): {Name: '输入', ControlType: EditControl},这是因为pip 下载的wxauto第三方库无法匹配微信客户端3.7的版本

  • 如果有遇到,可以通过Github的方式下载源码,直接修改源码
    在这里插入图片描述

    wxauto库信息:Author: tikic@qq.comSource: https://github.com/cluic/wxautoVersion: 3.3.5.3

微信最新版本需要重新适配,需修改 wxauto.py 代码

1.在 wxauto.py 的文件中找到 WeChat 的类,并添加下述方法    def ChangeWindow(self, window_title):        self.EditMsg = self.UiaAPI.EditControl(Name=f'{window_title}')        2.之后在 ChatWith 方法中加入如下代码    def ChatWith(self, who, RollTimes=None):        '''        打开某个聊天框        who : 要打开的聊天框好友名,str;  * 最好完整匹配,不完全匹配只会选取搜索框第一个        RollTimes : 默认向下滚动多少次,再进行搜索        '''        self.UiaAPI.SwitchToThisWindow()        self.ChangeWindow(who)  # [2] 加入如下方法,在每次更改聊天对象时调用 ChangeWindow 方法        ... ...

wxauto.py完整代码

#!python3# -*- coding: utf-8 -*-"""Author: tikic@qq.comSource: https://github.com/cluic/wxautoLicense: MIT LicenseVersion: 3.9.0.28"""import uiautomation as uiaimport win32gui, win32conimport win32clipboard as wcimport timeimport osAUTHOR_EMAIL = 'tikic@qq.com'UPDATE = '2023-02-25'VERSION = '3.9.0.28'class WxParam:    SYS_TEXT_HEIGHT = 33    TIME_TEXT_HEIGHT = 34    RECALL_TEXT_HEIGHT = 45    CHAT_TEXT_HEIGHT = 52    CHAT_IMG_HEIGHT = 117    SpecialTypes = ['[文件]', '[图片]', '[视频]', '[音乐]', '[链接]']class WxUtils:    def GetMessageInfos(Item, msglist=None):        msglist = msglist if msglist is not None else list()        if len(Item.GetChildren()) == 0:            msglist.append(Item.Name)        else:            for i in Item.GetChildren():                WxUtils.GetMessageInfos(i, msglist)        return [i for i in msglist if i]    def SplitMessage(MsgItem):        uia.SetGlobalSearchTimeout(0)        MessageInfos = WxUtils.GetMessageInfos(MsgItem)        MsgItemName = MsgItem.Name        if MsgItem.BoundingRectangle.height() == WxParam.SYS_TEXT_HEIGHT:            Msg = ('SYS', MsgItemName, MessageInfos)        elif MsgItem.BoundingRectangle.height() == WxParam.TIME_TEXT_HEIGHT:            Msg = ('Time', MsgItemName, MessageInfos)        elif MsgItem.BoundingRectangle.height() == WxParam.RECALL_TEXT_HEIGHT:            if '撤回' in MsgItemName:                Msg = ('Recall', MsgItemName, MessageInfos)            else:                Msg = ('SYS', MsgItemName, MessageInfos)        else:            Index = 1            User = MsgItem.ButtonControl(foundIndex=Index)            try:                while True:                    if User.Name == '':                        Index += 1                        User = MsgItem.ButtonControl(foundIndex=Index)                    else:                        break                Msg = (User.Name, MsgItemName, MessageInfos)            except:                Msg = ('SYS', MsgItemName, MessageInfos)        uia.SetGlobalSearchTimeout(10.0)        return Msg    def SetClipboard(data, dtype='text'):        '''复制文本信息或图片到剪贴板        data : 要复制的内容,str 或 Image 图像'''        if dtype.upper() == 'TEXT':            type_data = win32con.CF_UNICODETEXT        elif dtype.upper() == 'IMAGE':            from io import BytesIO            type_data = win32con.CF_DIB            output = BytesIO()            data.save(output, 'BMP')            data = output.getvalue()[14:]        else:            raise ValueError('param (dtype) only "text" or "image" supported')        wc.OpenClipboard()        wc.EmptyClipboard()        wc.SetClipboardData(type_data, data)        wc.CloseClipboard()    def Screenshot(hwnd, to_clipboard=True):        '''为句柄为hwnd的窗口程序截图        hwnd : 句柄        to_clipboard : 是否复制到剪贴板        '''        import pyscreenshot as shot        bbox = win32gui.GetWindowRect(hwnd)        win32gui.SetWindowPos(hwnd, win32con.HWND_TOPMOST, 0, 0, 0, 0, \  win32con.SWP_SHOWWINDOW | win32con.SWP_NOMOVE | win32con.SWP_NOSIZE)        win32gui.SetWindowPos(hwnd, win32con.HWND_NOTOPMOST, 0, 0, 0, 0, \  win32con.SWP_SHOWWINDOW | win32con.SWP_NOMOVE | win32con.SWP_NOSIZE)        win32gui.BringWindowToTop(hwnd)        im = shot.grab(bbox)        if to_clipboard:            WxUtils.SetClipboard(im, 'image')        return im    def SavePic(savepath=None, filename=None):        Pic = uia.WindowControl(ClassName='ImagePreviewWnd', Name='图片查看')        Pic.SendKeys('{Ctrl}s')        SaveAs = Pic.WindowControl(ClassName='#32770', Name='另存为...')        SaveAsEdit = SaveAs.EditControl(ClassName='Edit', Name='文件名:')        SaveButton = Pic.ButtonControl(ClassName='Button', Name='保存(S)')        PicName, Ex = os.path.splitext(SaveAsEdit.GetValuePattern().Value)        if not savepath:            savepath = os.getcwd()        if not filename:            filename = PicName        FilePath = os.path.realpath(os.path.join(savepath, filename + Ex))        SaveAsEdit.SendKeys(FilePath)        SaveButton.Click()        Pic.SendKeys('{Esc}')    def ControlSize(control):        locate = control.BoundingRectangle        size = (locate.width(), locate.height())        return size    def ClipboardFormats(unit=0, *units):        units = list(units)        wc.OpenClipboard()        u = wc.EnumClipboardFormats(unit)        wc.CloseClipboard()        units.append(u)        if u:            units = WxUtils.ClipboardFormats(u, *units)        return units    def CopyDict():        Dict = {}        for i in WxUtils.ClipboardFormats():            if i == 0:                continue            wc.OpenClipboard()            try:                content = wc.GetClipboardData(i)                wc.CloseClipboard()            except:                wc.CloseClipboard()                raise ValueError            if len(str(i)) >= 4:                Dict[str(i)] = content        return Dictclass WeChat:    def __init__(self):        self.UiaAPI = uia.WindowControl(ClassName='WeChatMainWndForPC')        self.SessionList = self.UiaAPI.ListControl(Name='会话')        self.EditMsg = self.UiaAPI.EditControl(Name='输入')        self.SearchBox = self.UiaAPI.EditControl(Name='搜索')        self.MsgList = self.UiaAPI.ListControl(Name='消息')        self.SessionItemList = []    def ChangeWindow(self, window_title):        self.EditMsg = self.UiaAPI.EditControl(Name=f'{window_title}')    def GetSessionList(self, reset=False):        '''获取当前会话列表,更新会话列表'''        self.SessionItem = self.SessionList.ListItemControl()        SessionList = []        if reset:            self.SessionItemList = []        for i in range(100):            try:                name = self.SessionItem.Name            except:                break            if name not in self.SessionItemList:                self.SessionItemList.append(name)            if name not in SessionList:                SessionList.append(name)            self.SessionItem = self.SessionItem.GetNextSiblingControl()        return SessionList    def Search(self, keyword):        '''        查找微信好友或关键词        keywords: 要查找的关键词,str   * 最好完整匹配,不完全匹配只会选取搜索框第一个        '''        self.UiaAPI.SetFocus()        time.sleep(0.2)        self.UiaAPI.SendKeys('{Ctrl}f', waitTime=1)        self.SearchBox.SendKeys(keyword, waitTime=1.5)        self.SearchBox.SendKeys('{Enter}')    def ChatWith(self, who, RollTimes=None):        '''        打开某个聊天框        who : 要打开的聊天框好友名,str;  * 最好完整匹配,不完全匹配只会选取搜索框第一个        RollTimes : 默认向下滚动多少次,再进行搜索        '''        self.UiaAPI.SwitchToThisWindow()        self.ChangeWindow(who)  # [2] 加入如下方法,在每次更改聊天对象时调用 ChangeWindow 方法        RollTimes = 10 if not RollTimes else RollTimes        def roll_to(who=who, RollTimes=RollTimes):            for i in range(RollTimes):                if who not in self.GetSessionList()[:-1]:                    self.SessionList.WheelDown(wheelTimes=3, waitTime=0.1 * i)                else:                    time.sleep(0.5)                    self.SessionList.ListItemControl(Name=who).Click(simulateMove=False)                    return 1            return 0        rollresult = roll_to()        if rollresult:            return 1        else:            self.Search(who)            return roll_to(RollTimes=1)    def SendMsg(self, msg, clear=True):        '''向当前窗口发送消息        msg : 要发送的消息        clear : 是否清除当前已编辑内容        '''        self.UiaAPI.SwitchToThisWindow()        if clear:            self.EditMsg.SendKeys('{Ctrl}a', waitTime=0)        self.EditMsg.SendKeys(msg, waitTime=0)        self.EditMsg.SendKeys('{Enter}', waitTime=0)    def SendFiles(self, *filepath, not_exists='ignore'):        """向当前聊天窗口发送文件        not_exists: 如果未找到指定文件,继续或终止程序        filepath (list): 要复制文件的绝对路径"""        key = ''        for file in filepath:            file = os.path.realpath(file)            if not os.path.exists(file):                if not_exists.upper() == 'IGNORE':                    print('File not exists:', file)                    continue                elif not_exists.upper() == 'RAISE':                    raise FileExistsError('File Not Exists: %s' % file)                else:                    raise ValueError('param not_exists only "ignore" or "raise" supported')            key += '' % file        self.EditMsg.SendKeys(' ', waitTime=0)        self.EditMsg.SendKeys('{Ctrl}a', waitTime=0)        self.EditMsg.SendKeys('{Ctrl}c', waitTime=0)        self.EditMsg.SendKeys('{Delete}', waitTime=0)        while True:            try:                data = WxUtils.CopyDict()                break            except:                pass        for i in data:            data[i] = data[i].replace(b'', key.encode())        data1 = {            '13': '',            '16': b'\x04\x08\x00\x00',            '1': b'',            '7': b''        }        data.update(data1)        wc.OpenClipboard()        wc.EmptyClipboard()        for k, v in data.items():            wc.SetClipboardData(int(k), v)        wc.CloseClipboard()        self.SendClipboard()        return 1    def SendClipboard(self):        '''向当前聊天页面发送剪贴板复制的内容'''        self.SendMsg('{Ctrl}v')    @property    def GetAllMessage(self):        '''获取当前窗口中加载的所有聊天记录'''        MsgDocker = []        MsgItems = self.MsgList.GetChildren()        for MsgItem in MsgItems:            MsgDocker.append(WxUtils.SplitMessage(MsgItem))        return MsgDocker    @property    def GetLastMessage(self):        '''获取当前窗口中最后一条聊天记录'''        uia.SetGlobalSearchTimeout(1.0)        MsgItem = self.MsgList.GetChildren()[-1]        Msg = WxUtils.SplitMessage(MsgItem)        uia.SetGlobalSearchTimeout(10.0)        return Msg    def LoadMoreMessage(self, n=0.1):        '''定位到当前聊天页面,并往上滚动鼠标滚轮,加载更多聊天记录到内存'''        n = 0.1 if n < 0.1 else 1 if n > 1 else n        self.MsgList.WheelUp(wheelTimes=int(500 * n), waitTime=0.1)    def SendScreenshot(self, name=None, classname=None):        '''发送某个桌面程序的截图,如:微信、记事本...        name : 要发送的桌面程序名字,如:微信        classname : 要发送的桌面程序类别名,一般配合 spy 小工具使用,以获取类名,如:微信的类名为 WeChatMainWndForPC'''        if name and classname:            return 0        else:            hwnd = win32gui.FindWindow(classname, name)        if hwnd:            WxUtils.Screenshot(hwnd)            self.SendClipboard()            return 1        else:            return 0

wxautoapi

来源地址:https://blog.csdn.net/qq877728715/article/details/131792307

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

【Python】通过第三方库wxauto自动化操作微信电脑客户端

下载Word文档到电脑,方便收藏和打印~

下载Word文档

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录