python --pywinauto操作微信

时间:2025-04-12 22:55:19
  1. PyWeChatSpy
  2. /mrsanshui/WeChatPYAPI/

感谢这位作者,解释挺详细

from pywinauto.application import Application
from pywinauto.keyboard import send_keys
import time
import psutil
import winreg


# 输入进程名,获取PID
def get_pid(p_name):
    pids = psutil.pids()
    for pid in pids:
        p = psutil.Process(pid)
        if p_name in p.name():
            return pid

def get_wechat_installation_path():
    key_path = r"Software\Tencent\WeChat"
    try:
        key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, key_path, 0, winreg.KEY_READ)
        value, _ = winreg.QueryValueEx(key, "InstallPath")
        return value[0].upper() + value[1:] + '\'
    except FileNotFoundError:
        print("找不到微信程序")
        return None

chat_name = "文件传输助手"  # 需要发送消息的聊天名称
message = "测试"  # 需要发送的消息
we_chat_path = get_wechat_installation_path()  # 微信路径  C:\Program Files (x86)\Tencent\WeChat

# 获取微信PID并获取微信窗口
we_chat_id = get_pid("")
app = Application(backend='uia').connect(process=we_chat_id)
we_chat_main_dialog = app.window(class_name='WeChatMainWndForPC')


# 微信挂在后台时,通过再次运行唤醒
if not we_chat_main_dialog.exists():
    tmp = Application().start(we_chat_path)

# 通过先最小化,再恢复使得窗口置顶
we_chat_main_dialog.minimize()
we_chat_main_dialog.restore()

# for control in we_chat_main_dialog.print_control_identifiers():
#     # 打印控件的类名和标题
#     print(control)

# 通过搜索,定位聊天
search_elem = we_chat_main_dialog.child_window(control_type='Edit', title='搜索')
search_elem.click_input()
search_elem.type_keys('^a').type_keys(chat_name)
time.sleep(1)
send_keys('{ENTER}')

# 点击要发送消息的聊天
chat_list = we_chat_main_dialog.child_window(control_type='List', title='会话')
for chat_item in chat_list.items():
    if chat_name in chat_item.element_info.name:
        chat_item.click_input()
        time.sleep(1)

# 获取聊天记录
message_list = we_chat_main_dialog.child_window(control_type='List', title='消息')
for message_item in message_list.items():
    print(message_item.window_text())

# 输入并发送消息
# app["Dialog"]["Edit1"].TypeKeys("E:\\")
# app["Dialog"]["Edit1"].TypeKeys("C:\\Users\\Administrator\\Desktop\\用印申请.pdf")
edit_elem = we_chat_main_dialog.child_window(control_type='Edit', title=chat_name)
edit_elem.click_input()
edit_elem.type_keys(message, with_spaces=True)
time.sleep(1)
send_keys('{ENTER}')

# send_keys(message)
# send_keys('{ENTER}')
# (2)

只发消息

“”"
实现自动发送消息
“”"

import time
import os
from  import send_keys #键盘
 
while True:
    time_now = ("%H:%M:%S", ())  # 获取当前时间
    sent_time = ("%H:%M:%S", ())  # 发送时间
    if time_now == sent_time:  # 当前时间等于发送时间则执行以下程序
        def open_app(app_dir):
            (app_dir)
 
        # 打开微信
        if __name__ == "__main__":
            app_dir = r'C:\Program Files (x86)\Tencent\WeChat\'  # 此处为微信的绝对路径
            open_app(app_dir)
            (1)
 
        #进入微信,模拟按键Ctrl+F
        send_keys('^f')
        send_keys('请输入联系人')
        (1)
        send_keys('{ENTER}') # 回车键必须全部大小
 
        #需要发送的消息内容
        message = '啦啦!!,是时候休息啦!Good night!!!'
        (1)
 
        # 输入聊天内容
        send_keys(message)
        # 回车发送消息
        send_keys('{ENTER}')
 
        (3)
        print('退出~~~')
 
        exit() # 退出程序

结合wxauto工具整合

import uiautomation as uia
import win32gui, win32con
import win32clipboard as wc
import time
import os
import psutil
from  import Application


COPYDICT = {}


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:

    @staticmethod
    def start_we_chat():
        # 输入进程名,获取PID
        def get_pid(p_name):
            pids = ()
            for pid in pids:
                p = (pid)
                if p_name in ():
                    return pid

        we_chat_path = r"D:\Program Files (x86)\Tencent\WeChat\"  # 微信路径  C:\Program Files (x86)\Tencent\WeChat

        # 获取微信PID并获取微信窗口
        we_chat_id = get_pid("")
        app = Application(backend='uia').connect(process=we_chat_id)
        we_chat_main_dialog = (class_name='WeChatMainWndForPC')

        # 微信挂在后台时,通过再次运行唤醒
        if not we_chat_main_dialog.exists():
            tmp = Application().start(we_chat_path)

        # 通过先最小化,再恢复使得窗口置顶
        we_chat_main_dialog.minimize()
        we_chat_main_dialog.restore()


    def SplitMessage(MsgItem):
        (0)
        MsgItemName = 
        if () == WxParam.SYS_TEXT_HEIGHT:
            Msg = ('SYS', MsgItemName, ''.join([str(i) for i in ()]))
        elif () == WxParam.TIME_TEXT_HEIGHT:
            Msg = ('Time', MsgItemName, ''.join([str(i) for i in ()]))
        elif () == WxParam.RECALL_TEXT_HEIGHT:
            if '撤回' in MsgItemName:
                Msg = ('Recall', MsgItemName, ''.join([str(i) for i in ()]))
            else:
                Msg = ('SYS', MsgItemName, ''.join([str(i) for i in ()]))
        else:
            Index = 1
            User = (foundIndex=Index)
            try:
                while True:
                    if  == '':
                        Index += 1
                        User = (foundIndex=Index)
                    else:
                        break
                Msg = (, MsgItemName, ''.join([str(i) for i in ()]))
            except:
                Msg = ('SYS', MsgItemName, ''.join([str(i) for i in ()]))
        (10.0)
        return Msg

    def SetClipboard(data, dtype='text'):
        '''复制文本信息或图片到剪贴板
        data : 要复制的内容,str 或 Image 图像'''
        if () == 'TEXT':
            type_data = win32con.CF_UNICODETEXT
        elif () == 'IMAGE':
            from io import BytesIO
            type_data = win32con.CF_DIB
            output = BytesIO()
            (output, 'BMP')
            data = ()[14:]
        else:
            raise ValueError('param (dtype) only "text" or "image" supported')
        ()
        ()
        (type_data, data)
        ()

    def Screenshot(hwnd, to_clipboard=True):
        '''为句柄为hwnd的窗口程序截图
        hwnd : 句柄
        to_clipboard : 是否复制到剪贴板
        '''
        import pyscreenshot as shot
        bbox = (hwnd)
        (hwnd, win32con.HWND_TOPMOST, 0, 0, 0, 0, \
                              win32con.SWP_SHOWWINDOW | win32con.SWP_NOMOVE | win32con.SWP_NOSIZE)
        (hwnd, win32con.HWND_NOTOPMOST, 0, 0, 0, 0, \
                              win32con.SWP_SHOWWINDOW | win32con.SWP_NOMOVE | win32con.SWP_NOSIZE)
        (hwnd)
        im = (bbox)
        if to_clipboard:
            (im, 'image')
        return im

    def SavePic(savepath=None, filename=None):
        Pic = (ClassName='ImagePreviewWnd', Name='图片查看')
        ('{Ctrl}s')
        SaveAs = (ClassName='#32770', Name='另存为...')
        SaveAsEdit = (ClassName='Edit', Name='文件名:')
        SaveButton = (ClassName='Button', Name='保存(S)')
        PicName, Ex = (().Value)
        if not savepath:
            savepath = ()
        if not filename:
            filename = PicName
        FilePath = ((savepath, filename + Ex))
        (FilePath)
        ()
        ('{Esc}')

    def ControlSize(control):
        locate = 
        size = ((), ())
        return size

    def ClipboardFormats(unit=0, *units):
        units = list(units)
        ()
        u = (unit)
        ()
        (u)
        if u:
            units = (u, *units)
        return units

    def CopyDict(self):
        Dict = {}
        for i in ():
            if i == 0:
                continue
            ()
            try:
                content = (i)
                ()
            except:
                ()
                raise ValueError
            if len(str(i)) >= 4:
                Dict[str(i)] = content
        return Dict


class WeChat:
    def __init__(self):
        WxUtils.start_we_chat()
         = (ClassName='WeChatMainWndForPC')
         = (Name='会话')
         = (Name='输入')
         = (Name='搜索')
         = (Name='消息')
         = []

    def GetSessionList(self, reset=False):
        '''获取当前会话列表,更新会话列表'''
         = ()
        SessionList = []
        if reset:
             = []
        for i in range(100):
            try:
                name = 
            except:
                break
            if name not in :
                (name)
            if name not in SessionList:
                (name)
             = ()
        return SessionList

    def Search(self, keyword):
        '''
        查找微信好友或关键词
        keywords: 要查找的关键词,str   * 最好完整匹配,不完全匹配只会选取搜索框第一个
        '''
        ()
        (0.2)
        ('{Ctrl}f', waitTime=1)
        (keyword, waitTime=1.5)
        ('{Enter}')

    def ChatWith(self, who, RollTimes=None):
        '''
        打开某个聊天框
        who : 要打开的聊天框好友名,str;  * 最好完整匹配,不完全匹配只会选取搜索框第一个
        RollTimes : 默认向下滚动多少次,再进行搜索
        '''
        ()
        RollTimes = 10 if not RollTimes else RollTimes

        def roll_to(who=who, RollTimes=RollTimes):
            for i in range(RollTimes):
                if who not in ()[:-1]:
                    (wheelTimes=3, waitTime=0.1 * i)
                else:
                    (0.5)
                    (Name=who).Click(simulateMove=False)
                    return 1
            return 0

        rollresult = roll_to()
        if rollresult:
            return 1
        else:
            (who)
            return roll_to(RollTimes=1)

    def SendMsg(self, msg, clear=True):
        '''向当前窗口发送消息
        msg : 要发送的消息
        clear : 是否清除当前已编辑内容
        '''
        ()
        if clear:
            ('{Ctrl}a', waitTime=0)
        (msg, waitTime=0)
        ('{Enter}', waitTime=0)

    def SendFiles(self, *filepath, not_exists='ignore'):
        """向当前聊天窗口发送文件
        not_exists: 如果未找到指定文件,继续或终止程序
        *filepath: 要复制文件的绝对路径"""
        global COPYDICT
        key = ''
        for file in filepath:
            file = (file)
            if not (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 += '<EditElement type="3" filepath="%s" shortcut="" />' % file
        if not key:
            return 0
        if not COPYDICT:
            (' ', waitTime=0)
            ('{Ctrl}a', waitTime=0)
            ('{Ctrl}c', waitTime=0)
            ('{Delete}', waitTime=0)
            while True:
                try:
                    COPYDICT = ()
                    break
                except:
                    pass
        ()
        ()
        (13, '')
        (16, b'\x04\x08\x00\x00')
        (1, b'')
        (7, b'')
        for i in COPYDICT:
            copydata = COPYDICT[i].replace(b'<EditElement type="0"><![CDATA[ ]]>', ()).replace(b'type="0"',
                                                                                                         b'type="3"')
            (int(i), copydata)
        ()
        ()
        return 1

    def SendClipboard(self):
        '''向当前聊天页面发送剪贴板复制的内容'''
        ('{Ctrl}v')

    @property
    def GetAllMessage(self):
        '''获取当前窗口中加载的所有聊天记录'''
        MsgDocker = []
        MsgItems = ()
        for MsgItem in MsgItems:
            ((MsgItem))
        return MsgDocker

    @property
    def GetLastMessage(self):
        '''获取当前窗口中最后一条聊天记录'''
        (1.0)
        MsgItem = ()[-1]
        Msg = (MsgItem)
        (10.0)
        return Msg

    def LoadMoreMessage(self, n=0.1):
        '''定位到当前聊天页面,并往上滚动鼠标滚轮,加载更多聊天记录到内存'''
        n = 0.1 if n < 0.1 else 1 if n > 1 else n
        (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 = (classname, name)
        if hwnd:
            (hwnd)
            ()
            return 1
        else:
            return 0

if __name__ == '__main__':
    a = WeChat()
    print()