pywinauto 简介
什么是pywinauto
pywinauto是一组用于自动化Microsoft Windows GUI的python模块。最简单的是,它允许您将鼠标和键盘操作发送到窗口对话框和控件。
pywinauto安装和启动
1. 安装pywinauto
在 Pycharm 底部的终端(Terminal)窗口中输入:
pip install pywinauto
提示success即安装成功了。
2. backend选择
我们安装好Pywinauto之后,首先要确定哪种可访问性技术(backend)可以用于我们的应用程序,在windows上受支持的有两种:
如果不能确定程序到底适用于那种backend,可以借助于GUI对象检查工具来查看,常用的检查工具有 Inspect.exe,Spy++ 。如果使用Inspect的UIA模式,可见的控件和属性更多的话,backend可选uia,反之,backend可选win32。
3. 控件查看工具-inspect
- inspect.exe下载链接:https://z4gvregzdz.feishu.cn/file/boxcnoI8GOg5aIWaYTVXL8hyWzc
- spy++下载链接:https://z4gvregzdz.feishu.cn/file/boxcnqlUR6yBhvuJsoFiUVrVGpe
将inspect左上角的下拉列表中切换到"UI Automation",然后鼠标点一下你需要测试的程序窗体,inspect就会显示相关信息,如下图所示。说明backend为uia
程序里面的任意一个部位其实都是控件,在inspect的控件树中都可以找到,是一层一层分级别的,可以一个个点开所有控件
完整操作步骤
通过pywinauto操作控件需要以下几个步骤:
- 第一步:创建实例化对象,得到的app是Application对象
- 第二步:选择窗口,得到的窗口是WindowSpecification对象
- 第三步:基于WindowSpecification对象使用其方法再往下查找,定位到具体的控件
- 第四步
接下来我们先看一个实例代码,(确保电脑版微信已经登录且前台显示在桌面上)按照上面的步骤获取微信的搜索文本框并点击,代码如下:
from pywinauto import Application# 第一步连接已有微信进程创建实例化对象PID = 12345 # 进程PID在任务管理器-详细信息可以查看后修改该值wechat_app = Application(backend='uia').connect(process=PID)# 第二步拿到微信主窗口main_window = wechat_app.window(class_name='WeChatMainWndForPC')# 第三步通过child_window方法查找搜索文本框search_box = main_window.child_window(control_type='Edit', title='搜索')# 第四步进行操作点击控件search_box.click_input()
执行后就会自动点击微信左上角搜索文本框了(注意:由于PID是变化的,以上代码一定能执行成功,后面会详细介绍)。
接下来,我们按照上面四步逐步讲解。
1. 创建实例化对象
以微信为例,这里介绍下常用的两种获取实例化程序的方式:
启动 start()
用于还没有启动软件的情况。timeout为超时参数(可选),若软件启动所需的时间较长可选timeout,默认超时时间为5s。 上代码:
start(self, cmd_line, timeout=app_start_timeout)
先确定微信是关闭的,我们通过上面方法启动微信并获取对应的实例化对象,如下:
from pywinauto import Application# 启动微信进程(注意路径中特殊字符的转义,/和\)app = Application(backend="uia").start(r'"E:\Program Files (x86)\Tencent\WeChat\WeChat.exe"')print(app)
运行后将会自动启动微信。
连接 connect()
用于连接已经启动的程序。connect()方式有多种:
- process
- handle
- path:进程的执行路径(GetModuleFileNameEx 模块会查找进程的每一个路径并与我们传入的路径去做比较)
- 参数组合(传递给pywinauto.findwindows.find_elements()这个函数)
app = Application().connect(process=12580)app = Application().connect(handle=0x234f1b)app = Application().connect(path="c:\windows\system32\notepad.exe")app = Application().connect(title_re=".*Notepad", class_name="Notepad")
下面我们介绍下通过进程PID与窗口句柄两种链接已启动程序的方式:
PID在任务管理器-详细信息可以查看。如下图,WeChat.exe的PID就是18364。 上代码:
from pywinauto.application import Application# 通过PID连接已有微信进程wechat_app = Application(backend='uia').connect(process=18364)print(wechat_app)
在星球中也有提到运利用第三方库psutil根据进程名获取进程PID的文章,有兴趣可以去看看,这里就不做详细介绍了。
在前面游戏自动化中学习了如何获取窗口的句柄,所以我们本着偷懒的原则还可以通过pywin32模块根据窗口名获取窗口句柄,然后获取根据句柄来获得主程序,代码如下:
import win32guifrom pywinauto.application import Applicationhwnd = win32gui.FindWindow(None, '微信')wechat_app = Application(backend='uia').connect(handle=hwnd)print(wechat_app)
注意:应用程序必须先准备就绪,才能使用connect()。当应用程序start()后没有超时和重连的机制,在pywinauto外启动启动应用程序,则需要睡眠或编程等待循环以等待应用程序完全启动。
实例对象app的常用方法
通过查看pywinauto的源码中application.py文件,可以看到app的所有属性方法,下面列举常用方法:
app.top_window()
返回应用程序当前顶部窗口,是WindowSpecification对象,可以继续使用对象的方法往下继续查找控件
如:app.top_window().child_window(title='搜索', control_type='Edit')
app.window(kwargs)
根据筛选条件,返回一个窗口,是WindowSpecification对象,可以继续适用对象的方法往下继续查找控件
微信主界面:app.window(class_name='WeChatMainWndForPC')
app.windows(kwargs)
根据筛选条件返回一个窗口列表,无条件默认全部,列表项为wrapped对象,可以使用wrapped对象的方法,注意不是WindowSpecification对象
[<uiawrapper.UIAWrapper - '微信', Dialog, -5995915281609806513>]
app.kill(soft=False)
强制关闭程序
app.cpu_usage()
返回CPU使用率百分比
app.wait_cpu_usage_lower(threshold=2.5, timeout=None, usage_interval=None)
等待进程CPU使用率百分比小于指定的阈值threshold
app.is64bit()
判断操作的进程是否是64-bit
简单演示下:
from pywinauto.application import Application# 通过PID连接已有微信进程wechat_app = Application(backend='uia').connect(process=18364)print(wechat_app.top_window())print(wechat_app.window())print(wechat_app.windows())print(wechat_app.cpu_usage())print(wechat_app.is64bit())
2. 选择窗口
pywinauto选择窗口有三种方式,获取到的窗口为 WindowSpecification对象。
以微信主界面窗口为例,先通过inspect工具查看微信的窗体信息:
按照上面的方法我们有三种方式来选取窗口,代码如下:
from pywinauto.application import Applicationimport win32gui# 根据应用程序窗口名获得句柄hwnd = win32gui.FindWindow(None, '微信')# 通过句柄连接已有微信进程app = Application(backend='uia').connect(handle=hwnd)dlg = app.window(class_name='WeChatMainWndForPC')# dlg = app.微信# dlg = app['微信']dlg.restore() # 将窗口恢复为正常大小,比如最小化的让他正常显示在桌面dlg.draw_outline(colour='red') # 控件外围画框,便于查看,支持'red', 'green', 'blue'
前面我们一直是手动先将微信窗口放置到前台,上面代码中我们利用restore()方法就可以自动将窗口恢复到正常大小了,利用draw_outline可以将控件外围画框,非常便于调试。
窗口的常用方法
下面则是窗口平时常用的一些方法:
# 以下几个只支持窗口模式的控件dlg.close() # 关闭界面dlg.minimize() # 最小化界面dlg.maximize() # 最大化界面dlg.restore() # 将窗口恢复为正常大小,比如最小化的让他正常显示在桌面dlg.get_show_state() # 正常0,最大化1,最小化2dlg.exists(timeout=None, retry_interval=None) # 判断是否存在# timeout:等待时间,一般默认5s# retry_interval:timeout内重试时间dlg.wait(wait_for, timeout=None, retry_interval=None) # 等待窗口处于特定状态dlg.wait_not(wait_for_not, timeout=None, retry_interval=None) # 等待窗口不处于特定状态,即等待消失# wait_for/wait_for_not:# * 'exists' means that the window is a valid handle# * 'visible' means that the window is not hidden# * 'enabled' means that the window is not disabled
本章小结
这一章咱们打开了桌面自动化的新世界大门,来回顾一下都学了啥:
pywinauto是干啥的? 简单说就是个能帮你自动操作Windows桌面程序的Python库。鼠标点击、键盘输入、窗口操作、控件交互,它都能搞定。安装起来也简单,一条 pip install pywinauto 就完事。
backend怎么选? 这是初学者最容易懵的地方。pywinauto支持两种backend:win32和uia。win32是默认的,适合一些老的Windows程序(MFC、VB6等);uia更强大,能识别到更多控件,适合WinForms、WPF、Qt5等现代程序。如果不确定用哪个,就用inspect工具看看,哪种模式下能看到的控件更多就用哪种。
inspect工具咋用? 这是个查看控件信息的利器。打开后把左上角的模式切换到"UI Automation",然后鼠标点一下目标窗口,就能看到窗口里所有的控件树了。一层一层的,每个控件的类型、名称、位置都能看清楚。这个工具是写自动化脚本的好帮手,写代码前先用inspect摸清控件结构,写起来就顺了。
操作控件分几步? 四步走:第一步创建Application对象(用start启动程序或用connect连接已有程序);第二步选择窗口(用window方法);第三步定位控件(用child_window方法);第四步执行操作(click、type_keys等)。这四步是固定套路,记住就行。
start和connect啥区别? start是用来启动还没运行的程序的,connect是用来连接已经在运行的程序的。比如微信已经打开了,就用connect;如果微信没开,就用start。connect有好几种连接方式:通过PID、通过句柄、通过进程路径、通过窗口标题等,灵活得很。
窗口对象能干啥? 窗口对象有很多实用方法:close()关闭窗口、minimize()最小化、maximize()最大化、restore()恢复正常大小、exists()判断窗口是否存在、wait()等待窗口达到某种状态。这些方法在自动化流程控制中特别好用,比如等某个窗口加载完再继续下一步。
WindowSpecification对象是啥? 这是pywinauto里用来描述窗口或控件的对象。你可以把它理解成一个"查找条件",还没真正找到控件,只是告诉pywinauto你要找什么样的控件。只有当你调用具体方法(比如click、type_keys)的时候,pywinauto才会真正去查找并操作控件。
掌握了这些基础,后面就能用pywinauto来自动化各种Windows桌面程序了,比如自动操作微信、自动填表、自动测试软件等等。