V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
爱意满满的作品展示区。
pytth
V2EX  ›  分享创造

Python 模拟人手操作微信,一个 Python 操作微信电脑版的脚本

  •  1
     
  •   pytth · 2022-08-11 22:25:59 +08:00 · 2125 次点击
    这是一个创建于 616 天前的主题,其中的信息可能已经有所发展或是发生改变。

    一直以来,都有很多人通过各种办法去实现微信机器人,或者是控制微信电脑版去实现微信的 API ,例如 Hook 微信、iPad 协议、web 微信协议、Android 微信协议、以及基于浏览器的 puppet ,方法很多,但是各种方法都有各自的一些缺点。

    本文使用的方法是通过 Python 去调用 Windows API 实现模拟人工操作的方式去实现控制微信电脑版,这也是一种不错的办法,但稳定性、精确度还是稍微差了点。

    代码

    本文所涉及到的模块会比较多,其中 PIL 是用于图片识别来实现一些读取聊天记录的功能,win32clipboard 主要实现是模拟输入,win32api 、win32con 、win32gui 、pyautogui 就是核心的库,主要用于调用 API 去模拟人手操作微信电脑版。

    winwxpy.py

    import pyautogui
    import time
    import win32api
    import win32con
    import win32gui
    import win32clipboard as w
    from PIL import ImageGrab
    import requests
    import base64
    
    def FindWindow(chatroom):
        win = win32gui.FindWindow('WeChatMainWndForPC',chatroom)
        print("找到窗口句柄:%x" % win)
        if win != 0:
            win32gui.ShowWindow(win, win32con.SW_SHOWMINIMIZED)
            win32gui.ShowWindow(win, win32con.SW_SHOWNORMAL)
            win32gui.ShowWindow(win, win32con.SW_SHOW)
            win32gui.SetWindowPos(win, win32con.HWND_TOP, 0, 0, 500, 700, win32con.SWP_SHOWWINDOW)
            win32gui.SetForegroundWindow(win)  # 获取控制
            time.sleep(1)
            tit = win32gui.GetWindowText(win)
            print('已启动 ['+str(tit)+'] 窗口')
        else:
            print('找不到 [%s ] 窗口' % chatroom)
            exit()
    
    # 设置和粘贴剪贴板
    def ClipboardText(ClipboardText):
        w.OpenClipboard()
        w.EmptyClipboard()
        w.SetClipboardData(win32con.CF_UNICODETEXT, ClipboardText)
        w.CloseClipboard()
        time.sleep(1)
        win32api.keybd_event(17,0,0,0)
        win32api.keybd_event(86,0,0,0)
        win32api.keybd_event(86,0,win32con.KEYEVENTF_KEYUP,0)
        win32api.keybd_event(17,0,win32con.KEYEVENTF_KEYUP,0)
    
    # 模拟发送动作
    def SendMsg():
        win32api.keybd_event(18, 0, 0, 0)
        win32api.keybd_event(83,0,0,0)
        win32api.keybd_event(18,0,win32con.KEYEVENTF_KEYUP,0)
        win32api.keybd_event(83,0,win32con.KEYEVENTF_KEYUP,0)
    
    # 模拟发送微信文本消息
    def SendWxMsg(wxid,sendtext):
        # 先启动微信
        FindWindow('微信')
        time.sleep(1)
        # 定位到搜索框
        pyautogui.moveTo(143, 39)
        pyautogui.click()
        # 搜索微信
        ClipboardText(wxid)
        time.sleep(1)
        # 进入聊天窗口
        pyautogui.moveTo(155, 120)
        pyautogui.click()
        # 粘贴文本内容
        ClipboardText(sendtext)
        # 发送
        SendMsg()
        print('已发送')
        # 关闭微信窗口
        time.sleep(1)
        pyautogui.moveTo(683, 16)
        pyautogui.click()
    
    # 模拟发送文件消息(图片、文档、压缩包等)
    def SendWxFileMsg(wxid,imgpath):
        # 先启动微信
        FindWindow('微信')
        time.sleep(1)
        # 定位到搜索框
        pyautogui.moveTo(143, 39)
        pyautogui.click()
        # 搜索微信
        ClipboardText(wxid)
        time.sleep(1)
        # 进入聊天窗口
        pyautogui.moveTo(155, 120)
        pyautogui.click()
        # 选择文件
        pyautogui.moveTo(373, 570)
        pyautogui.click()
        ClipboardText(imgpath)
        time.sleep(1)
        pyautogui.moveTo(784, 509)
        pyautogui.click()
        # 发送
        SendMsg()
        print('已发送')
        # 关闭微信窗口
        time.sleep(1)
        pyautogui.moveTo(683, 16)
        pyautogui.click()
    
    # 转发群里最新的一条消息
    def ZhuanfaMsg(wxid,groupname):
        # 先启动微信
        FindWindow('微信')
        time.sleep(1)
        # 定位到搜索框
        pyautogui.moveTo(143, 39)
        pyautogui.click()
        # 搜索群
        ClipboardText(groupname)
        time.sleep(1)
        # 进入群窗口
        pyautogui.moveTo(155, 120)
        pyautogui.click()
        # 开始转发
        pyautogui.moveTo(484, 439)
        time.sleep(1)
        pyautogui.rightClick()
        pyautogui.moveTo(543, 454)
        time.sleep(1)
        pyautogui.click()
        # 搜索用户
        ClipboardText(wxid)
        time.sleep(1)
        pyautogui.moveTo(828, 406)
        pyautogui.click()
        time.sleep(1)
        # 确定转发
        pyautogui.moveTo(1108, 755)
        pyautogui.click()
    
    # 获取你的个人信息(昵称、微信号)
    def GetYourInfo():
        # 先启动微信
        FindWindow('微信')
        time.sleep(1)
        # 点击你的头像
        pyautogui.moveTo(28, 56)
        pyautogui.click()
        time.sleep(1)
        # 用户信息截图
        userinfo = (20, 60, 319, 284)
        userinfo_img = ImageGrab.grab(userinfo)
        userinfo_img.save('userinfo.png')
        # 识别用户信息截图
        request_url = "https://aip.baidubce.com/rest/2.0/ocr/v1/accurate_basic"
        f = open('userinfo.png', 'rb')
        img = base64.b64encode(f.read())
        params = {"image":img}
        access_token = '传入你的 Token'
        request_url = request_url + "?access_token=" + access_token
        headers = {'content-type': 'application/x-www-form-urlencoded'}
        response = requests.post(request_url, data=params, headers=headers)
        if response:
            print (response.json())
        time.sleep(1)
        # 关闭微信窗口
        time.sleep(1)
        pyautogui.moveTo(683, 16)
        pyautogui.click()
    
    # 获取好友微信的个人信息(昵称、微信号)
    def GetFriendInfo(wxid):
        # 先启动微信
        FindWindow('微信')
        time.sleep(1)
        # 定位到搜索框
        pyautogui.moveTo(143, 39)
        pyautogui.click()
        # 搜索微信
        ClipboardText(wxid)
        time.sleep(1)
        # 进入聊天窗口
        pyautogui.moveTo(160, 93)
        pyautogui.click()
        time.sleep(1)
        # 点击右上角···
        pyautogui.moveTo(678, 43)
        pyautogui.click()
        time.sleep(1)
        pyautogui.moveTo(801, 51)
        pyautogui.click()
        # 用户信息截图
        userinfo = (802, 54, 1085, 331)
        userinfo_img = ImageGrab.grab(userinfo)
        userinfo_img.save('userinfo.png')
        # 识别用户信息截图
        request_url = "https://aip.baidubce.com/rest/2.0/ocr/v1/accurate_basic"
        f = open('userinfo.png', 'rb')
        img = base64.b64encode(f.read())
        params = {"image":img}
        access_token = '传入你的 Token'
        request_url = request_url + "?access_token=" + access_token
        headers = {'content-type': 'application/x-www-form-urlencoded'}
        response = requests.post(request_url, data=params, headers=headers)
        if response:
            print (response.json())
        time.sleep(1)
        # 关闭微信窗口
        time.sleep(1)
        pyautogui.moveTo(683, 16)
        pyautogui.click()
        pyautogui.click()
    
    # 获取群人数
    def GetCharRoomUserNum(groupname):
        # 先启动微信
        FindWindow('微信')
        time.sleep(1)
        # 定位到搜索框
        pyautogui.moveTo(143, 39)
        pyautogui.click()
        # 搜索群
        ClipboardText(groupname)
        time.sleep(1)
        # 进入群窗口
        pyautogui.moveTo(155, 120)
        pyautogui.click()
        # 群人数区域截图
        userinfo = (310, 0, 659, 47)
        userinfo_img = ImageGrab.grab(userinfo)
        userinfo_img.save('chatroom.png')
        # 识别群人数截图
        # 开发文档:https://cloud.baidu.com/doc/OCR/s/Ck3h7y2ia
        request_url = "https://aip.baidubce.com/rest/2.0/ocr/v1/accurate_basic"
        f = open('chatroom.png', 'rb')
        img = base64.b64encode(f.read())
        params = {"image":img}
        access_token = '传入你的 Token'
        request_url = request_url + "?access_token=" + access_token
        headers = {'content-type': 'application/x-www-form-urlencoded'}
        response = requests.post(request_url, data=params, headers=headers)
        if response:
            print (response.json())
        time.sleep(1)
        # 关闭微信窗口
        time.sleep(1)
        pyautogui.moveTo(683, 16)
        pyautogui.click()
    
    
    # 发布群公告
    def AddGorupNotice(groupname,NoticeText):
        # 先启动微信
        FindWindow('微信')
        time.sleep(1)
        # 定位到搜索框
        pyautogui.moveTo(143, 39)
        pyautogui.click()
        # 搜索群
        ClipboardText(groupname)
        time.sleep(1)
        # 进入群窗口
        pyautogui.moveTo(155, 120)
        pyautogui.click()
        # 定位到群名称
        pyautogui.moveTo(363, 33)
        pyautogui.click()
        # 定位到群公告
        time.sleep(1)
        pyautogui.moveTo(731, 509)
        pyautogui.click()
        # 粘贴群公告内容
        ClipboardText(NoticeText)
        # 确认发布群公告
        time.sleep(1)
        pyautogui.moveTo(288, 500)
        pyautogui.click()
        pyautogui.moveTo(312, 297)
        pyautogui.click()
    
    # 邀请好友进群
    def ReqFriendsToGroup(groupname,wxid):
        # 先启动微信
        FindWindow('微信')
        time.sleep(1)
        # 定位到搜索框
        pyautogui.moveTo(143, 39)
        pyautogui.click()
        # 搜索群
        ClipboardText(groupname)
        time.sleep(1)
        # 进入群窗口
        pyautogui.moveTo(155, 120)
        pyautogui.click()
        # 定位到群名称
        pyautogui.moveTo(363, 33)
        pyautogui.click()
        # 定位到邀请
        time.sleep(1)
        pyautogui.moveTo(852, 300)
        pyautogui.click()
        # 搜索好友
        ClipboardText(wxid)
        # 发出邀请
        time.sleep(1)
        pyautogui.moveTo(232, 197)
        pyautogui.click()
        time.sleep(1)
        pyautogui.moveTo(493, 561)
        pyautogui.click()
        time.sleep(1)
        pyautogui.moveTo(395, 427)
        pyautogui.click()
    
    # 获取好友最新的聊天记录
    def GetChatRecord(wxid):
        # 先启动微信
        FindWindow('微信')
        time.sleep(1)
        # 搜索微信号
        pyautogui.moveTo(166, 38)
        pyautogui.click()
        ClipboardText(wxid)
        time.sleep(1)
        pyautogui.moveTo(197, 123)
        pyautogui.click()
        # 聊天内容区域截图
        userinfo = (314, 68, 683, 549)
        userinfo_img = ImageGrab.grab(userinfo)
        userinfo_img.save('chatrecord.png')
        # 识别当前聊天窗口截图
        # 开发文档:https://cloud.baidu.com/doc/OCR/s/Ck3h7y2ia
        request_url = "https://aip.baidubce.com/rest/2.0/ocr/v1/accurate_basic"
        f = open('chatrecord.png', 'rb')
        img = base64.b64encode(f.read())
        params = {"image":img}
        access_token = '传入你的 Token'
        request_url = request_url + "?access_token=" + access_token
        headers = {'content-type': 'application/x-www-form-urlencoded'}
        response = requests.post(request_url, data=params, headers=headers)
        if response:
            print (response.json())
    
    # 置顶群或好友
    def SetTop(groupname_wxid):
        # 先启动微信
        FindWindow('微信')
        time.sleep(1)
        # 定位到搜索框
        pyautogui.moveTo(143, 39)
        pyautogui.click()
        # 搜索群或好友
        ClipboardText(groupname_wxid)
        time.sleep(1)
        # 进入窗口
        pyautogui.moveTo(155, 120)
        pyautogui.click()
        # 打开设置
        pyautogui.moveTo(684, 38)
        pyautogui.click()
        time.sleep(1)
        # 置顶
        pyautogui.moveTo(914, 227)
        pyautogui.click()
        time.sleep(1)
        pyautogui.moveTo(682, 18)
        pyautogui.click()
        print('已将'+str(groupname_wxid)+'置顶')
    
    
    # 添加微信
    def AddWx(wxid):
        # 先启动微信
        FindWindow('微信')
        time.sleep(1)
        # 定位到添加微信位置
        pyautogui.moveTo(25, 151)
        pyautogui.click()
        time.sleep(1)
        pyautogui.moveTo(278, 39)
        pyautogui.click()
        time.sleep(1)
        pyautogui.moveTo(153, 39)
        pyautogui.click()
        time.sleep(1)
        # 搜索微信号
        ClipboardText(wxid)
        time.sleep(1)
        pyautogui.moveTo(183, 91)
        pyautogui.click()
        time.sleep(2)
        # 对搜索微信号结果进行截图
        userinfo = (306, 68, 565, 240)
        userinfo_img = ImageGrab.grab(userinfo)
        userinfo_img.save('addwx.png')
        # 对搜索微信号结果进行识别
        # 开发文档:https://cloud.baidu.com/doc/OCR/s/Ck3h7y2ia
        request_url = "https://aip.baidubce.com/rest/2.0/ocr/v1/accurate_basic"
        f = open('addwx.png', 'rb')
        img = base64.b64encode(f.read())
        params = {"image":img}
        access_token = '传入你的 Token'
        request_url = request_url + "?access_token=" + access_token
        headers = {'content-type': 'application/x-www-form-urlencoded'}
        response = requests.post(request_url, data=params, headers=headers)
        if response:
            print (response.json())
        # 添加
        time.sleep(1)
        pyautogui.moveTo(435, 203)
        pyautogui.click()
        time.sleep(1)
        pyautogui.moveTo(300, 621)
        pyautogui.click()
        time.sleep(1)
        pyautogui.moveTo(278, 37)
        pyautogui.click()
        print('已向'+str(wxid)+'发送添加好友请求')
        pyautogui.moveTo(682, 18)
        pyautogui.click()
    
    # 发送文本消息(微信号或微信昵称或备注,需要发送的文本消息)
    # SendWxMsg('微信号','Python 发送微信消息')
    
    # 发送文件消息(图片、文档、压缩包等)
    # SendWxFileMsg('微信号',r"文件路径")
    
    # 转发群里最新的一条消息(微信号或微信昵称或备注,群名称)
    # ZhuanfaMsg('微信号','群名称')
    
    # 获取你的个人信息(昵称、微信号)
    # GetYourInfo('微信号')
    
    # 获取好友微信的个人信息(昵称、微信号)
    # GetFriendInfo('微信号')
    
    # 获取微信群人数
    # GetCharRoomUserNum('群名称')
    
    # 发布群公告
    # AddGorupNotice('群名称','Python 发布群公告')
    
    # 邀请好友进群
    # ReqFriendsToGroup('群名称','微信号')
    
    # 获取好友最新的聊天记录
    # GetChatRecord('微信号')
    
    # 置顶群或好友
    # SetTop('微信号')
    
    # 添加微信
    # AddWx('微信号')
    

    如何使用

    以上的 winwxpy.py 已经将常用的一些操作写成了函数,只需要调用对应的函数,传入微信号、内容、群名称等参数进去即可调用其中的功能,目前已实现的功能如下:

    # 发送文本消息(微信号或微信昵称或备注,需要发送的文本消息)
    # SendWxMsg('微信号','Python 发送微信消息')
    
    # 发送文件消息(图片、文档、压缩包等)
    # SendWxFileMsg('微信号',r"文件路径")
    
    # 转发群里最新的一条消息(微信号或微信昵称或备注,群名称)
    # ZhuanfaMsg('微信号','群名称')
    
    # 获取你的个人信息(昵称、微信号)
    # GetYourInfo('微信号')
    
    # 获取好友微信的个人信息(昵称、微信号)
    # GetFriendInfo('微信号')
    
    # 获取微信群人数
    # GetCharRoomUserNum('群名称')
    
    # 发布群公告
    # AddGorupNotice('群名称','Python 发布群公告')
    
    # 邀请好友进群
    # ReqFriendsToGroup('群名称','cbzqx88')
    
    # 获取好友最新的聊天记录
    # GetChatRecord('微信号')
    
    # 置顶群或好友
    # SetTop('微信号')
    
    # 添加微信
    # AddWx('微信号')
    

    需要用哪个那就直接将注释去掉...

    版本要求

    脚本基于目前最新版微信( 3.7.5.23 )进行匹配。 Python3.7

    二次开发方向

    例如引入 http 进行远程调用函数实现远程控制微信。你可以在一台 Windows 服务器登录电脑版微信,然后使用这个脚本,实现远程控制,就可以实现微信的 API 了。或者是在本地 windows 系统,通过内网穿透方式去调用 http 来控制微信。

    其他

    代码写的比较烂,勿吐槽。因为没有认真学过 Python ,都是想做什么就搜,然后临时学学...写这个是因为自己工作有这方面的需求,用了一段时间比较稳定了,就分享出来大几玩玩,其实也没有那么好玩。

    6 条回复    2022-08-17 10:19:28 +08:00
    ggp1ot2
        1
    ggp1ot2  
       2022-08-12 09:22:13 +08:00
    目测是基于微信窗口位置的?如果移动了窗口需要手动修改定位吗?
    dlsflh
        2
    dlsflh  
       2022-08-12 11:56:10 +08:00 via Android
    @ggp1ot2 我没看代码,但我用过 pyautogui ,可以通过图像识别来实现自动跟踪窗口位置。
    zagfai
        3
    zagfai  
       2022-08-12 15:17:24 +08:00
    把 Python 用得像极了按键精灵,哈哈哈
    pytth
        4
    pytth  
    OP
       2022-08-12 23:33:13 +08:00 via iPhone
    @ggp1ot2 每个操作都会初始化窗口并且设置窗口大小。根据自定的窗口坐标来点击。
    superrichman
        5
    superrichman  
       2022-08-13 14:01:23 +08:00 via Android
    @zagfai pyautogui 就是 Python 版的按键精灵,而且是跨平台的
    yohn89
        6
    yohn89  
       2022-08-17 10:19:28 +08:00
    这个继续扩展下去可了不得,电信诈骗的狂喜
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3046 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 14:46 · PVG 22:46 · LAX 07:46 · JFK 10:46
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.