python基于pywinauto实现PC端操作微信自动化-幸运编程经验

python基于pywinauto实现PC端操作微信自动化

一、 pywinauto安装和启动

安装:


pip install pywinauto

启动(实例化程序):以微信示例


from pywinauto.application import Application

# 常用方式一:连接已有微信进程(进程号在 任务管理器-详细信息 可以查看)

app = Application(backend=‘uia‘).connect(process=8948)

# 常用方式二:启动微信进程 (注意路径中特殊字符的转义,/和\,不注意有时会出错)

app = Application(backend="uia").start(r‘C:\Program Files (x86)\Tencent\WeChat\WeChat.exe‘) 

结束:


# 结束进程

app.kill()

二、backend选择 和 控件查看工具inspect

1.backend选择和inspect介绍

我们安装好Pywinauto之后,首先要确定哪种可访问性技术(backend)可以用于我们的应用程序,在windows上受支持的有两种:


Win32 API (backend= "win32") 默认的backend


MS UI Automation (backend="uia")


如果不能确定程序到底适用于那种backend,可以借助于GUI对象检查工具来做,常用的检查工具有Inspect.ex,Spy++ ,下载地址:https://github.com/blackrosezy/gui-inspect-tool


将inspect左上角的下拉列表中切换到“UI Automation”,然后鼠标点一下你需要测试的程序窗体,inspect就会显示相关信息,如下图所示。说明backend为uia


 


 程序里面的任意一个部位其实都是控件,在inspect的控件树中都可以找到,是一层一层分级别的,可以一个个点开所有控件


2.打印元素

我们拿到控件后,是可以将该控件下的所有子控件及其属性以树形结构打印出来的:


# 拿到微信主窗口

win_main_Dialog = app.window(class_name=‘WeChatMainWndForPC‘)


# 判断是否为dialog,一个微信是一个dialog,就是窗口

print(win_main_Dialog.is_dialog)


# 给控件画个红色框便于看出是哪个

win_main_Dialog.draw_outline(colour = ‘red‘)


# 打印当前窗口的所有controller(控件和属性)

win_main_Dialog. print_control_identifiers(depth=None, filename=None)

# 源码内部函数名链式赋值了,都能用,一样的

# print_ctrl_ids = dump_tree = print_control_identifiers

depth:打印的深度,缺省时打印最大深度。

filename:将返回的标识存成文件(生成的文件与当前运行的脚本在同一个路径下)

eg:dlg. print_control_identifiers(filename =’a.txt’)


打印出来的文档树就是inspect中的控件树完全展开的样子,都是有层级的,和微信程序中的各个元素是一一对应的:


 三、控件查找定位

# 直接找窗口

win_main_Dialog = app.window(class_name=‘WeChatMainWndForPC‘)


# 主窗口下的某个窗口,不管层级的找

chat_list = win_main_Dialog.child_window(control_type=‘List‘, title=‘会话‘)

first = chat_list.items()[0] # 第一个聊天项  列表支持items(),支持循环,支持索引

chat_list.scroll(direction=‘down‘, amount=‘page‘) # 向下滚动一页


# 详情页修改备注操作  parent()和children()都是只往上或往下查找一个层级,所有满足的放进列表

details_page = win_main_Dialog.child_window(class_name=‘ContactProfileWnd‘) # 窗口下的某个窗口

we_id = details_page.child_window(title="微信号:", control_type="Text").parent().children()[1].window_text() # 窗口的爸爸的第二个儿子的文字

alia = details_page.child_window(title="微信号:", control_type="Text").parent().parent().children()[0].children()[0].window_text()

edit_btn = details_page.child_window(title="备   注", control_type="Text").parent().children()[1]

edit_btn.click_input()

btn_modify_name_edit = edit_btn

# 先ctrl+a选中所有然后再type_keys替换

btn_modify_name_edit.type_keys(‘^a‘).type_keys(‘备注名字‘, with_spaces=True)


# descendants查找所有后代中满足的,不管层级,所有满足的放进列表

btn_return = win_main_Dialog.child_window(control_type=‘ToolBar‘).parent().descendants(control_type=‘Button‘)

btn_return[0].click_input()

 


title="微信团队" # 对应inspect界面的Name,打印出来也会显示


class_name=‘WeChatLoginWndForPC‘ # 对应ClassName


control_type="Window" # 对应LocalizedControlType的英文版,打印出来后也会显示

control_type="Text"

control_type="Button"

control_type="List"

control_type="ListItem"

control_type=‘MenuItem‘

control_type=‘ToolBar‘


auto_id=‘FileTypeControlHost‘

控件常见特征

四、控件自带的的方法

1. 点击和输入

# 左点击,可以点进源码,还有double_click_input,right_click_input等

edit_btn.click_input()


# 先ctrl+a选中所有然后再type_keys替换,和我们选中然后修改一样的

edit_btn.type_keys(‘^a‘).type_keys(‘备注名字‘, with_spaces=True)

SHIFT                            +      

CTRL                             ^      

ALT                               %

空格键                            {SPACE}


BACKSPACE                        {BACKSPACE}、{BS}   or   {BKSP}      

BREAK                            {BREAK}      

CAPS   LOCK                      {CAPSLOCK}      

DEL   or   DELETE                {DELETE}   or   {DEL}      

DOWN   ARROW                     {DOWN}      

END                              {END}      

ENTER                            {ENTER}   or   ~      

ESC                              {ESC}      

HELP                             {HELP}      

HOME                             {HOME}      

INS   or   INSERT                {INSERT}   or   {INS}      

LEFT   ARROW                     {LEFT}      

NUM   LOCK                       {NUMLOCK}      

PAGE   DOWN                      {PGDN}      

PAGE   UP                        {PGUP}      

PRINT   SCREEN                   {PRTSC}      

RIGHT   ARROW                    {RIGHT}      

SCROLL   LOCK                    {SCROLLLOCK}      

TAB                              {TAB}      

UP   ARROW                       {UP}     

+                                {ADD}      

-                                {SUBTRACT}      

*                                {MULTIPLY}      

/                                {DIVIDE}

常用快捷键

2.对控件截图并保存

ctrl_qrcode = self.win_login.child_window(title=‘二维码‘, control_type=‘Image‘)

if ctrl_qrcode.exists(): 

    ctrl_qrcode.capture_as_image().save(img_path)

3.窗口的等待

窗口加载需要时间,我们又不能一直sleep就需要等待,等待窗口出现或者等待窗口关闭:


save_dialog.wait(‘ready‘,timeout=2)

save_dialog.close()

save_dialog.wait_not(‘visible‘)


# ‘exists‘:窗口是有效的句柄

# ‘visible‘:窗口未隐藏,常用

# ‘enabled‘:未禁用窗口

# ‘ready‘:窗口可见并启用,常用

# ‘active‘:窗口处于活动状态

4.其他

# 顶层窗口

dlg = app.top_window()

# 点方法取值

print(dlg.class_name()) #‘WeChatMainWndForPC‘

# 滚动

chat_list.scroll(direction=‘up‘, amount=‘page‘)

五、鼠标操作

导入:


from pywinauto import mouse

常见操作:


# 移动鼠标

mouse.move(coords=(x, y))


# 指定位置,鼠标左击

mouse.click(button=‘left‘, coords=(40, 40))


# 鼠标双击

mouse.double_click(button=‘left‘, coords=(140, 40))


# 将属性移动到(140,40)坐标处按下

mouse.press(button=‘left‘, coords=(140, 40))


# 将鼠标移动到(300,40)坐标处释放,

mouse.release(button=‘left‘, coords=(300, 40))


# 右键单击指定坐标

mouse.right_click(coords=(400, 400))


# 鼠标中键单击指定坐标(很少用的到)

mouse.wheel_click(coords=(400, 400))


# 滚动鼠标 wheel_dist指定鼠标滚轮滑动,正数往上,负数往下。

mouse.scroll(coords=(1200,300),wheel_dist=-3)

示例:


# 以控件中心为起点,滚动

def mouse_scroll(control, distance):

    rect = control.rectangle()

    cx = int((rect.left+rect.right)/2)

    cy = int((rect.top + rect.bottom)/2)

    mouse.scroll(coords=(cx, cy), wheel_dist=distance)

mouse_scroll(control=win_main_Dialog.child_window(control_type=‘List‘, title=‘联系人‘), distance=-5)

六、键盘操作

和控件自己的type_keys方法效果一样,但是更快,那个是从前到后啪啪啪的输入,这个是一下就出来了那种


在发送文件和图片的时候可以使用键盘模块,复制粘贴,比啪啪啪输入路径再发送速度快多了


import keyboard

import io


for line in io.StringIO(msg):

    keyboard.write(line.strip()) #

    keyboard.send(‘ctrl+enter‘)   

keyboard.write(chat_name)

keyboard.send(‘enter‘)

keyboard.send(‘ctrl+v‘)