在介绍 pywinauto 前,先说一下这个工具的使用方法,就是如何去操作目标应用程序,第一步:实例化要操作的进程,得到 Application 对象;跟 App 自动化一样,window 上面有很多应用程序,先指定要操作哪个程序。第二步:选择窗口,得到一个 WindowSpecification 对象;应用程序打开,就是一个窗口,进入到这个窗口,就能获取当前窗口的元素信息。第三步:基于 WindowSpecification 对象,定位具体的控件(元素)。第四步:对控件执行相应的操作。

  使用之前先安装该工具,很简单,cmd命令行输入:pip install pywinauto 即可。

  基于上面的思路,就可以开展自动化工作了。首先获取 Application 对象,有2种方式:1、启动一个应用程序;2、直接连接已经打开的应用程序。在这之前,要确定当前应用程序的的开发技术,要不然无法获取程序信息。pywinauto 支持 win32(MFC、VB6、VCL等开发语言) 和 MS UI Automation API(WinForms、WPF、Store apps QT5、浏览器),默认是 win32。那么,怎么才能知道当前应用程序使用哪种开发技术,这里推荐2款工具:inspect.exeAccessibility Insights。以 inspect.exe 为例,打开该工具,左上角使用 UI Automation,如果有相关信息,就是uia ,如果拒绝链接,就是win32。这类工具网上很多,如果找不到,可以找我要。

find_elements() 方法获取应用窗口,该方法适合已经打开的窗口,不传参数,默认查找所有窗口,关键字参数见下方介绍,可以缩小范围。这样在使用 connect() 方法获取 Application 对象就比较方便。

from pywinauto import Application,findwindows
findwindows.find_elements()
==> [ <win32_element_info.HwndElementInfo - '无标题 - Notepad', Notepad, 854118>, <win32_element_info.HwndElementInfo - 'PyWinAuto - xxx@163.com - 印象笔记', Qt5152QWindowIcon, 788708> ]

findwindows.find_window(title="无标题 - Notepad")
==> 854118

  启动一个新的应用:app=Application(backend=“uia”).start(‘notepad.exe’),start 方法传入要打开的应用程序,如果找不到,就要输入全路径。这里就是打开了本机的记事本。

  连接已经打开的应用:app=Application(backend=“uia”).connect(title_re=‘.印象笔记.’),connect 方法连接已经打开的程序,有好几种方式,我介绍比较常用的:

process

可以使用pid 进行绑定;

handle

可以使用窗口句柄绑定;

path

可以使用程序路径绑定;

title_re

根据窗口标题名字绑定;

class_name

根据窗口类名绑定;

  这里我比较喜欢用 title_re 参数连接应用程序,每个应用程序打开,在左上角都会有一个 titile,title_re 是利用正则匹配窗口,也可以直接使用 title 参数,但是,如果名字比较长,显得麻烦;使用 process、handle、calss_name 去连接,还需要去查,不如 title_re 方便。具体看情况使用。

  到这里,就可以获取到一个 Application 对象,然后可以操作该对象的方法,例如:

  • app.process:获取进程 id;
  • app.kill:强制关闭该应用程序;
  • app.top_window():返回顶层窗口对象;.dump_tree() 方法可以获取当前窗口结构信息,跟后文的 print_control_identifiers() 方法一样;
  • app.windows():获取当前应用所有窗口;
  • app.cpu_usage():返回指定秒数期间的CPU使用百分比;
  • app.wait_cpu_usage_lower(threshold=2.5, timeout=None, usage_interval=None):等待进程CPU使用率百分比小于指定的阈值threshold.
  • app.is_process_running():当前进程是否运行中;

  有了Application对象,还需要获取窗口对象,app.windows() 是获取所有窗口对象,返回一个列表,包含窗口的标题、类、句柄,这些信息对于连接到具体的窗口很有用。获取窗口对象:app.window(title=“DingTalk”),也可以使用 app[“Dialog”],我比较喜欢使用 window()方法,该方法有很多关键字参数可用:

class_name

类名;

title

控件标题,就是inspect 中的name;

auto_id

inspect 中的automationId 属性;

control_type

inspect 中 LocalizedControlType属性(不是中文,是英文,control_type值有MenuBar、Button、Edit、MenuItem等);

title_re

title正则匹配;

best_match

模糊匹配title;

handle

NativeWindowHandle;

  这里的关键字参数,不仅在 window() 方法可用,在 connect() 方法、child_window() 方法中也可以使用,还可以联合使用,大家可以多试试。

# 获取钉钉窗口对象
dlg = app.window(title="钉钉")
dlg = app.window(class_name="Dialog")
dlg = app["Dialog"]

  窗口对象WindowSpecification 有一些常用的方法,如下:

  • dlg.maximize():窗口最大化;
  • dlg.minimize():窗口最小化;
  • dlg.restore():还原窗口;
  • dlg.get_show_state():获取窗口显示状态,最大化是1,正常是0;
  • dlg.close():关闭窗口;
  • dlg.rectangle():获取窗口坐标;
  • draw_outline(colour=“red”) :给窗口/控件加外框,便于识别;
  • exists(timeout=None, retry_interval=None):判断窗口是否存在;
  • wait(state, timeout=None, retry_interval=None):等待窗口;
  • wait_not(state, timeout=None, retry_interval=None):等待窗口;
  • dlg.print_control_identifiers(depth=None):获取窗口结构信息,depth 指定结构深度;除了通过工具获取控件(元素)信息,这个方法也是重要的途径,工作中也会经常用到。

  通过窗口对象可以获取当前窗口的结构信息,然后就可以获取窗口中的控件,方法如下:

  • dlg[“控件名称”],这种方式常用,但是注意中文乱码问题。
  • dlg.xxx,这种方式不建议,如果控件的名称中间有空格,那就不好使了。
  • dlg.child_window(title=,best_match=,…),上面的常见关键字参数都可以使用,获取窗口指定控件(递归查找)found_index 指定索引,如果有多个相同的控件,可以加该参数。我常用这种方式。
  • dlg.children():获取 窗口/控件 子元素(直系),返回一个list;
  • dlg.descendants() 查找所有符合条件的子孙元素,返回一个list,可以添加条件缩小范围;
app = Application("uia").connect(title="钉钉")
dlg = app.window(title="钉钉")

search = dlg.child_window(title="搜索", control_type="Edit")
search.click_input()
search.type_keys("Alan")
time.sleep(1)
SendKeys("{ENTER}")

chat = dlg.child_window(control_type = "Document",class_name="Chrome_RenderWidgetHostHWND")
chat.wait("ready",10,1)

time.sleep(2)
content = chat.descendants(control_type = "ListItem")

  当然,APP、UI里面的层级定位、下标定位也是支持的;

  层级定位

同花顺策略交易 python pywinauto 同花顺_python

new_dlg = dlg.child_window(best_match="Form")
new_dlg.child_window(best_match="Edit").set_text("123")

  下标定位

# 定位 记事本 输入框,并输入内容,跟上图一样

dlg.children()[0].children()[0].type_keys("层级定位")

  在关键字参数中,介绍了 control_type,在 inspect.exe 工具显示的是中文,但是不能使用,要使用英文类型,这个参数也常用,所以给大家列举一下常见的控件类型;

Button

按钮控件

Calendar

日历控件,例如日期选取器

CheckBox

复选框控件

ComboBox

组合框控件

Custom

标识一个控件,该控件不属于已定义的控件类型之一

DataGrid

数据网格控件

DataItem

数据项控件

Document

文档控件

Edit

编辑控件,例如一个文本框

Group

其他控件的容器的组控件

Header

标题控件,它是一个用作信息的行和列标签的容器

HeaderItem

标题项,它是信息的行或列的标签

Hyperlink

超链接控件

Image

图像控件

List

列表控件,例如列表框

ListItem

列表项控件,它是列表控件的子项

Menu

菜单控件,例如应用程序窗口中的一个顶级菜单

MenuBar

菜单栏控件,它通常包含一组顶级菜单

MenuItem

菜单项控件

Pane

格控件

ProgressBar

进度条控件,该控件以可视方式指示一个长时间操作的进度

RadioButton

单选按钮控件,这种选择机制只允许在组中选择一项

ScrollBar

滚动条控件,例如应用程序窗口中的滚动条

Separator

分隔符

Slider

滑块控件

Spinner

微调控件

SplitButton

拆分按钮,该按钮将执行默认操作,并且还可以扩展到其他可能操作的列表。

StatusBar

状态栏控件

Tab

选项卡控件

TabItem

选项卡项控件,它代表选项卡控件的一页

Table


Text

编辑控件,例如一个文本框或多格式文本框

Thumb

标识滚动条中可拖到不同位置的控件

TitleBar

窗口上的标题栏

ToolBar

工具栏,例如应用程序窗口中包含一组命令按钮的控件

ToolTip

工具提示控件,将指针移动到一个控件上方时或有时使用键盘 Tab 键切换到一个控件时将出现此信息窗口。

Tree

树控件

TreeItem

标识 TreeItem 控件中的一个节点

Window

包含子对象的窗口框架

  有关控件的属性及操作在下文一一讲解,谢谢大家的关注!