当前位置: 首页 > news >正文

GUI自动化之pywinauto

目录

一、说明

二、安装pywinauto

三、安装UI对象检查⼯具

四、pywinauto常见操作

1. 打开程序

2. 定位窗口

3. 窗口操作

4. 定位控件

4.1 best_match来定位

4.2 child_window()定位

5. 等待

5.1 wait/wait_not()

5.2 wait_until()

6. 控件的操作

6.1 点击

6.2 文本

7. 鼠标操作

8. 键盘操作

8.1 输入文本

8.2 按键输入

9. 菜单控件的操作

10. 列表控件的操作

一、说明

Pywinauto是⼀款基于Python的跨平台GUI⾃动化库,专⻔针对Windows桌⾯应⽤程序设计,其核⼼能⼒在于通过模拟⽤⼾交互⾏为(如⿏标点击、键盘输⼊)实现对窗⼝、对话框及内部控件的精准定 位与操作,适⽤于⾃动化测试、批量任务处理及⽇常办公流程优化等场景。 该库通过两种底层技术(backend="win32"和backend="uia")适配不同框架开发的应⽤程序:

  • win32模式适⽤于传统MFC、VB6等旧架构

  •  uia模式则⽀持现代WinForms、WPF、Qt5及浏览器等应⽤

pywinauto的局限性

  • 仅⽀持Windows:⽆法⽤于MacLinux平台。

  • 对⾮标准控件⽀持有限:某些⾃定义控件可能需要额外处理。

        注意:pywinauto⽀持传统Windows原⽣应⽤框架和部分跨平台框架(需在Windows运⾏),以下 是⼀些⽆法使⽤pywinauto 实现GUI⾃动化的应⽤程序分类,以及原因

1. 基于Web的应⽤程序

  • 原因: pywinauto 是为本地Windows应⽤程序设计的,⽆法直接与基于浏览器的Web应⽤程序交互。Web应⽤程序的⾃动化通常需要使⽤如Selenium这样的⼯具 。

  • ⽰例:GoogleChrome中打开的任何⽹⻚或基于Web的企业应⽤。

2. 基于⾃定义渲染引擎的应⽤程序

  • 原因:某些应⽤程序(如使⽤Flutter、ReactNative或其他跨平台框架开发的应⽤)可能使⽤ ⾃定义的渲染引擎,这些引擎不会暴露标准的WindowsUI⾃动化接口(如Win32或UIA)。

  • ⽰例:企业微信、某些使⽤Flutter开发的桌⾯应⽤。

二、安装pywinauto

安装pywinauto

pip install pywinauto

安装完成后,可以通过以下命令验证安装:

pip list

如果输出中包含pywinauto,则说明安装成功。

三、安装UI对象检查⼯具

        在讲解selenium实现web⾃动化时,定位⻚⾯的元素是必须要的,如何进⾏元素定位?打开⻚⾯开发 者⼯具,可以直接进⾏元素定位,定位到元素之后才能对指定元素进⾏⼀系列的操作,对于GUI⾃动化 也是⼀样,要想对界⾯的元素进⾏操作,我们得先会“找元素”,⽽找元素我们需要⽤UI对象检查⼯ 具, UI对象检查⼯具有很多,诸如Spy++、Inspect.exe、UISpy,这些⼯具基本都⻓得⼀样,且操作上基 本⽆差,我使⽤UISpy⼯具来进⾏UI对象检查。

UISpy是⼀款由微软提供的⼯具,专⻔⽤于UI⾃动化测试。它允许测试⼈员查看应⽤程序的UI⾃动 化模型,包括控件树、属性和事件。UISpy特别适⽤于编写UI⾃动化脚本,因为它提供了⼀个可视 化的界⾯来帮助测试⼈员选择UI元素,并且可以模拟⽤⼾对这些UI元素的操作。

四、pywinauto常见操作

1. 打开程序

我们要控制软件的第一件事就是启动一个Windows软件,每一个软件(进程)都是一个Application对象

实例化Application对象的时候可以传入一个backend参数,可选值为win32(默认)和uia 

  • win32对应的框架:MFC、VB6、VCL、简单的 WinForms 控件和大多数旧的遗留应用程序

  • uia对应的框架:WinForms、WPF、商店应用程序、Qt5、浏览器

如果无法知道要测试的软件是属于哪种框架,可以使用 Inspect(对应uia)Spy++(对应win32)看看,你看哪个显示得更全就选哪个。Inspect和Spy++需要自己安装一下

下面是Application对象的主要方法

方法常用参数说明
start()cmd_line、timeout、retry_interval通过cmd命令启动一个软件(进程)
connect()process、handle、path、timeout连接一个进程,一般是使用进程号(任务管理器可以看到)

打开程序

Application(backend="uia").start("D:\应用商店下载安装的地方\WPS Office\ksolaunch.exe")
  • cmd_line:这是启动应⽤程序的命令⾏字符串。它必须包含应⽤程序的路径和名称,还可以包含启 动参数(绝对路径)

连接已经打开的应用程序

#获取应⽤程序对应的pid 
#app = Application(backend="uia").connect(process=app.process)
app = Application(backend="uia").connect(process=31528)#通过句柄连接 
app = Application(backend="uia").connect(handle=65552)
  • process :⽬标的进程ID

  • handle :⽬标的窗⼝句柄

注意:连接到已在运⾏的进程,该动作仅根据⼀个参数执⾏

2. 定位窗口

方法常用参数说明
window()title、title_re、class_name、best_match获取单个窗口(WindowSpecification)
app.window(title='',...)

app是start或connect返回到对象

  • title :⽂本为指定值的元素。

  • title_re :⽂本匹配指定正则表达式的元素。

  • best_match :标题与指定值相似的元素。

  • class_name :窗⼝类为指定值的元素。

  • class_name_re :类名匹配指定正则表达式的元素。

import time
from pywinauto.application import Application
from pywinauto import Application# 连接到一个应用程序
app = Application(backend="uia").start("D:\应用商店下载安装的地方\wangyiweidaofanyi\YoudaoDict.exe")
time.sleep(5)# 获取主窗口
#title--精确匹配
main_window = app.window(title="网易有道翻译")# title_re-正则匹配
main_window = app.window(title_re=".*易有道翻*.")#class_name--精确匹配 
main_window = app.window(class_name="YodaoMainWndClass")#class_name--正则匹配
main_window = app.window(class_name_re=".*MainWndClass")#best_match-模糊匹配
main_window = app.window(best_match="网易有道翻译Pane")# 打印所有控件标识符
main_window.print_control_identifiers()

3. 窗口操作

⽅法功能描述返回值
close()关闭窗口⽆返回值
maximize()将窗⼝最⼤化
minimize ()最⼩化窗
restore()窗⼝恢复正常⼤⼩
get_show_state()获取窗⼝的显⽰状态

返回⼀个整数值,表⽰窗⼝的状态:

0:正常

1:最⼤化

2:最⼩化

is_dialog()检查控件是否是顶级窗口返回布尔值: True 表⽰是顶级窗口, False 表⽰ 不是顶级窗口
is_maximized()检查窗是否处于最⼤化状态返回布尔值: True 表⽰窗口已最⼤化, False 表 ⽰未最⼤化
is_minimized()检查窗是否处于最⼩化状态返回布尔值: True 表⽰窗已最⼩化, False 表 ⽰未最⼩化
is_normal()检查窗是否处于正常状 态(既未最⼩化也未最⼤ 化)返回布尔值: True 表⽰窗处于正常状态, False 表⽰未处于正常状态
import time
from pywinauto import Application# 连接到一个记事本
app = Application(backend="uia").connect(process=56372)
time.sleep(3)
# 获取主窗口
main_window = app.window(class_name="Notepad")
# 等待
main_window.wait('exists')
# 最大化
main_window.maximize()
print("is_minimized:",main_window.is_minimized())
# 最小化
main_window.minimize()
print("is_maximized:",main_window.is_maximized())
# 复原
main_window.restore()
print("is_normal:",main_window.is_normal())
# 获取窗⼝的显⽰状态
print("get_show_state:",main_window.get_show_state())
# 检查控件是否是顶级窗口
print("is_dialog",main_window.is_dialog())
# 关闭
main_window.close()

4. 定位控件

在使⽤pywinauto进行自动化操作时,程序启动后,首先需要定位到目标窗口。窗口是所有控件的容 器,只有成功定位到窗口,才能进⼀步操作窗口内的控件。控件是窗口功能的具体体现,包括按钮、 文本框、列表等,对控件的操作是自动化任务的核心。然而,在对控件进行操作之前,必须先完成控 件的定位。定位控件是确保操作准确性的关键步骤,也是自动化流程的基础。

常见控件示例:

分类控件名称说明
窗⼝与对话框对话框(Dialog)⽤于与⽤⼾交互,如显⽰警告、确认操作或输⼊信息。
窗格(Pane)通常作为窗⼝的⼀部分,⽤于显⽰特定内容或功能。
输⼊控件按钮(Button)⽤于触发操作,如点击按钮执⾏某个功能。
编辑栏(Edit)⽤于输⼊或编辑⽂本,⽀持多⾏或单⾏输⼊。
组合框(ComboBox)结合⽂本框和列表框,⽤⼾可以选择预定义选项或输⼊⾃ 定义值。
列表框(ListBox)⽤于显⽰可选择的项⽬列表,⽀持单选或多选。
菜单控件菜单(Menu)⽤于提供功能选项,通常位于窗⼝顶部。
菜单项(MenuItem)菜单中的具体选项,点击后执⾏对应功能。
弹出菜单(PopupMenu)右键单击时弹出的菜单,⽤于快速访问常⽤功能。
列表显⽰控件列表显⽰控件(ListView)⽤于以表格形式显⽰数据,⽀持多列显⽰和排序。
容器控件组框(GroupBox)⽤于对控件进⾏分组,提⾼界⾯的可读性和组织性。
选择控件复选框(CheckBox)⽤于多选操作,⽤⼾可以勾选多个选项。
单选框(RadioButton)⽤于互斥选择,⽤⼾只能选择⼀个选项。
显⽰控件状态栏(StatusBar)通常位于窗⼝底部,⽤于显⽰应⽤状态或提⽰信息。
静态内容(Static)⽤于显⽰静态⽂本或图像,通常不可编辑。
导航控件树状视图(TreeView)⽤于展⽰分层数据,如⽂件夹结构或组织结构。
选项卡控件(TabControl)⽤于在有限空间内组织多个⻚⾯或选项卡,每个选项卡可 以包含不同的内容。
⼯具控件⼯具栏(Toolbar)⽤于放置常⽤按钮或⼯具,⽅便⽤⼾快速操作。
⼯具提⽰(ToolTips)当⿏标悬停在控件上时显⽰提⽰信息,帮助⽤⼾理解控件 功能。
头部内容头部内容(Header)通常⽤于显⽰标题或表头信息,如表格的列标题。

定位控件,需要借助前面学到的 print_control_identifiers() ⽅法,打印窗口及其子控件的标识符信息

import time
from pywinauto import Application# 连接到一个记事本
app = Application(backend="uia").connect(process=28304)
time.sleep(3)
# 获取主窗口
main_window = app.window(class_name="Notepad")
# 等待
main_window.wait('exists')
# 打印所有控件标识符
main_window.print_control_identifiers()
Dialog - '新建 文本文档.txt - Notepad'    (L733, T131, R1601, B985)
['Dialog', '新建 文本文档.txt - Notepad', '新建 文本文档.txt - NotepadDialog', 'Dialog0', 'Dialog1']
child_window(title="新建 文本文档.txt - Notepad", control_type="Window")| | Pane - ''    (L741, T224, R1593, B937)| ['Pane', '新建 文本文档.txtPane', 'Pane0', 'Pane1', '新建 文本文档.txtPane0', '新建 文本文档.txtPane1']|    | |    | Document - ''    (L741, T224, R1593, B937)|    | ['新建 文本文档.txtDocument', 'Document']| | Pane - ''    (L791, T143, R1150, B183)| ['Pane2', '新建 文本文档.txtPane2']|    | |    | Pane - ''    (L791, T143, R1150, B183)|    | ['Pane3', '新建 文本文档.txtPane3']|    |    | |    |    | TabControl - ''    (L791, T143, R1150, B183)|    |    | ['TabControl', 'TabControl添加新标签页', '新建 文本文档.txtTabControl']|    |    | child_window(auto_id="Tabs", control_type="Tab")|    |    |    | |    |    |    | ListBox - ''    (L793, T143, R1103, B183)|    |    |    | ['ListBox', '新建 文本文档.txtListBox']|    |    |    | child_window(auto_id="TabListView", control_type="List")|    |    |    |    | |    |    |    |    | TabItem - '新建 文本文档.txt. 未修改。'    (L796, T143, R1103, B183)|    |    |    |    | ['TabItem', '新建 文本文档.txt. 未修改。TabItem', '新建 文本文档.txt. 未修改。']|    |    |    |    | child_window(title="新建 文本文档.txt. 未修改。", control_type="TabItem")|    |    |    |    |    | |    |    |    |    |    | Static - '新建 文本文档.txt'    (L812, T153, R930, B172)|    |    |    |    |    | ['新建 文本文档.txtStatic', 'Static', '新建 文本文档.txt', 'Static0', 'Static1']|    |    |    |    |    | child_window(title="新建 文本文档.txt", control_type="Text")|    |    |    |    |    | |    |    |    |    |    | Button - '关闭标签页'    (L1052, T148, R1092, B178)|    |    |    |    |    | ['关闭标签页Button', '关闭标签页', 'Button', 'Button0', 'Button1']|    |    |    |    |    | child_window(title="关闭标签页", auto_id="CloseButton", control_type="Button")|    |    |    | |    |    |    | Button - '添加新标签页'    (L1107, T149, R1147, B179)|    |    |    | ['添加新标签页Button', 'Button2', '添加新标签页']|    |    |    | child_window(title="添加新标签页", auto_id="AddButton", control_type="Button")|    |    | |    |    | Pane - '记事本自动保存进度。下次打开记事本时,你的所有内容都将可用。'    (L0, T0, R0, B0)|    |    | ['Pane4', '记事本自动保存进度。下次打开记事本时,你的所有内容都将可用。', '记事本自动保存进度。下次打开记事本时,你的所有内容都将可用。Pane']|    |    | child_window(title="记事本自动保存进度。下次打开记事本时,你的所有内容都将可用。", auto_id="TeachingTip", control_type="Pane")| | Pane - ''    (L741, T183, R1593, B224)| ['Pane5', '新建 文本文档.txtPane4']|    | |    | Pane - ''    (L741, T183, R1593, B224)|    | ['Pane6', '新建 文本文档.txtPane5']|    |    | |    |    | Menu - ''    (L741, T183, R951, B223)|    |    | ['Menu', '新建 文本文档.txtMenu', 'Menu0', 'Menu1']|    |    | child_window(auto_id="MenuBar", control_type="MenuBar")|    |    |    | |    |    |    | MenuItem - '文件'    (L746, T183, R806, B223)|    |    |    | ['MenuItem', '文件MenuItem', '文件', 'MenuItem0', 'MenuItem1']|    |    |    | child_window(title="文件", auto_id="File", control_type="MenuItem")|    |    |    | |    |    |    | MenuItem - '编辑'    (L816, T183, R876, B223)|    |    |    | ['MenuItem2', '编辑MenuItem', '编辑']|    |    |    | child_window(title="编辑", auto_id="Edit", control_type="MenuItem")|    |    |    | |    |    |    | MenuItem - '查看'    (L886, T183, R946, B223)|    |    |    | ['查看', 'MenuItem3', '查看MenuItem']|    |    |    | child_window(title="查看", auto_id="View", control_type="MenuItem")|    |    | |    |    | Button - '标题'    (L1016, T183, R1087, B223)|    |    | ['标题', 'Button3', '标题Button']|    |    | child_window(title="标题", control_type="Button")|    |    | |    |    | Button - '列表'    (L1087, T183, R1157, B223)|    |    | ['列表', 'Button4', '列表Button']|    |    | child_window(title="列表", control_type="Button")|    |    | |    |    | Button - '加粗(Ctrl+B)'    (L1158, T183, R1198, B223)|    |    | ['加粗(Ctrl+B)', '加粗(Ctrl+B)Button', 'Button5']|    |    | child_window(title="加粗(Ctrl+B)", control_type="Button")|    |    | |    |    | Button - '斜体(Ctrl+I)'    (L1198, T183, R1238, B223)|    |    | ['斜体(Ctrl+I)', '斜体(Ctrl+I)Button', 'Button6']|    |    | child_window(title="斜体(Ctrl+I)", control_type="Button")|    |    | |    |    | Button - '链接(Ctrl+K)'    (L1238, T183, R1278, B223)|    |    | ['链接(Ctrl+K)Button', '链接(Ctrl+K)', 'Button7']|    |    | child_window(title="链接(Ctrl+K)", control_type="Button")|    |    | |    |    | Button - '清除格式设置(Ctrl+空格)'    (L1278, T183, R1318, B223)|    |    | ['清除格式设置(Ctrl+空格)', '清除格式设置(Ctrl+空格)Button', 'Button8']|    |    | child_window(title="清除格式设置(Ctrl+空格)", control_type="Button")|    |    | |    |    | Button - '设置'    (L1545, T183, R1583, B223)|    |    | ['设置', 'Button9', '设置Button']|    |    | child_window(title="设置", auto_id="SettingsButton", control_type="Button")|    |    | |    |    | Dialog - ''    (L0, T0, R0, B0)|    |    | ['Dialog2']|    |    | child_window(auto_id="PrivacyTeachingTip", control_type="Window")|    |    | |    |    | Dialog - ''    (L0, T0, R0, B0)|    |    | ['Dialog3']|    |    | child_window(auto_id="CowriterTeachingTip", control_type="Window")| | Pane - ''    (L741, T937, R1593, B977)| ['Pane7', '  行 1,列 1Pane', '  行 1,列 1Pane0', '  行 1,列 1Pane1']|    | |    | Pane - ''    (L741, T937, R1593, B977)|    | ['Pane8', '  行 1,列 1Pane2']|    |    | |    |    | Static - '  行 1,列 1'    (L761, T947, R840, B967)|    |    | ['  行 1,列 1', '  行 1,列 1Static', 'Static2']|    |    | child_window(title="  行 1,列 1", auto_id="ContentTextBlock", control_type="Text")|    |    | |    |    | Static - '0 个字符'    (L872, T947, R930, B967)|    |    | ['0 个字符', 'Static3', '0 个字符Static']|    |    | child_window(title="0 个字符", auto_id="ContentTextBlock", control_type="Text")|    |    | |    |    | Static - '纯文本'    (L1024, T937, R1084, B977)|    |    | ['纯文本Static', 'Static4', '纯文本']|    |    | child_window(title="纯文本", auto_id="ContentTextBlock", control_type="Text")|    |    | |    |    | Static - ' 100%'    (L1192, T947, R1233, B967)|    |    | [' 100%Static', ' 100%', 'Static5']|    |    | child_window(title=" 100%", auto_id="ContentTextBlock", control_type="Text")|    |    | |    |    | Static - ' Windows (CRLF)'    (L1277, T947, R1388, B967)|    |    | [' Windows (CRLF)', ' Windows (CRLF)Static', 'Static6']|    |    | child_window(title=" Windows (CRLF)", auto_id="ContentTextBlock", control_type="Text")|    |    | |    |    | Static - ' UTF-8'    (L1436, T947, R1480, B967)|    |    | [' UTF-8', 'Static7', ' UTF-8Static']|    |    | child_window(title=" UTF-8", auto_id="ContentTextBlock", control_type="Text")| | TitleBar - ''    (L0, T0, R0, B0)| ['TitleBar']|    | |    | Menu - '系统'    (L742, T140, R770, B168)|    | ['Menu2', '系统Menu', '系统', '系统0', '系统1']|    | child_window(title="系统", auto_id="MenuBar", control_type="MenuBar")|    |    | |    |    | MenuItem - '系统'    (L742, T140, R770, B168)|    |    | ['MenuItem4', '系统MenuItem', '系统2']|    |    | child_window(title="系统", control_type="MenuItem")|    | |    | Button - '最小化'    (L1415, T132, R1475, B169)|    | ['最小化Button', 'Button10', '最小化']|    | child_window(title="最小化", control_type="Button")|    | |    | Button - '最大化'    (L1475, T132, R1534, B169)|    | ['最大化', 'Button11', '最大化Button']|    | child_window(title="最大化", control_type="Button")|    | |    | Button - '关闭'    (L1534, T132, R1594, B169)|    | ['关闭', '关闭Button', 'Button12']|    | child_window(title="关闭", control_type="Button")
4.1 best_match来定位

best_match有两种定位方式:

  • main_window.文件(不能带空格,不推荐)

  • main_window["文件"]

import time
from pywinauto import Application# 连接到一个记事本
app = Application(backend="uia").connect(process=28304)
time.sleep(3)
# 获取主窗口
main_window = app.window(class_name="Notepad")
# 等待窗⼝变为可⻅状态,确保窗⼝已经加载完成
main_window.wait('visible')
# 通过窗⼝的标题获取菜单对象
menu=main_window["文件"]
# 打印父亲控件
print(menu.parent())

4.2 child_window()定位

        child_window() 和定位窗⼝的⽅法 window() 参数⼀样,可以通过标题或者类名进行精确匹配、模糊匹配等,在这⾥额外拓展几个进⾏控件定位时需要用到的参数:

属性名称描述
control_type具有此控件类型的元素(字符串;⽤于UIAutomation元素)
auto_id具有此⾃动化ID的元素(⽤于UIAutomation元素)
found_index返回的已过滤⼦元素的索引,索引下标从0开始
import time
from pywinauto import Application# 连接到一个记事本
app = Application(backend="uia").connect(process=28304)
time.sleep(3)
# 获取主窗口
main_window = app.window(class_name="Notepad")
# 等待窗⼝变为可⻅状态,确保窗⼝已经加载完成
main_window.wait('visible')
# 通过控件的属性(标题、⾃动ID和控件类型)定位菜单栏对象 
# 也可以通过这三个属性的其中一个,来定位,但是不能有重复
menu=main_window.child_window(title="编辑",auto_id="Edit", control_type="MenuItem")
# 打印父亲控件
print(menu.parent())

若存在多个控件的 auto_id 相同,可通过添加索引参数来定位:

注意,若元素值为空,或不是唯⼀的情况下,都会导致定位失败,索引从0开始

5. 等待

        GUI应用程序行为通常不稳定,脚本需要等待,直到出现新窗口或关闭/隐藏现有窗口。pywinauto可以隐式地(默认超时)灵活地等待对话框初始化,或者明确地使⽤专用方法/函数来帮助您使代码更容易和更可靠。

5.1 wait/wait_not()
wait(self, wait_for, timeout=None, retry_interval=None)
wait_not(self, wait_for_not, timeout=None, retry_interval=None)

参数说明:

1. wait_for :表⽰选择的窗口状态

  • exists :表⽰窗口是⼀个有效的句柄 

  • visible :表⽰窗口不隐藏,可以看到 

  • enable :表⽰窗口未被禁⽤,可操作 

  • ready :表⽰窗口可⻅且已启⽤ 

  • active :表⽰窗口处于活动状态

2. timeout :表⽰超时

3. retry_interval :表⽰重试时间间隔,单位为秒s

注意:wait_notwait() 类似, wait 是等待处于某种状态,而wait_not 是等待不处于某种状态,这⾥以wait为例说明

使用示例:existsvisible

import time
from pywinauto import Application# 连接到一个记事本
app = Application(backend="uia").connect(process=59164 )
# 获取主窗口
main_window = app.window(class_name="Notepad")#检查窗⼝是有效的句柄
main_window.wait('exists')
#检查窗⼝是否可⻅
main_window.wait('visible')
#检查窗⼝是否未被禁⽤
main_window.wait('enabled')
#检查窗⼝是否准备就绪
main_window.wait('ready')

窗口被最小化之后,在桌面就不可见了,因此最小化时需要将等待状态改为 "exists" ,应用程序界面在桌面可见时等待状态可以设置为 "visible"

enabled表示窗口未被禁用,可操作 

import time
from pywinauto import Application# 打开一个计算器
app = Application(backend="uia").connect(process=1136)
# 获取主窗口
main_window = app.window(title="计算器")
main_window.wait("visible",timeout=10)#启⽤的按钮
enable_btn = main_window.child_window(title="记忆减法", auto_id="MemMinus", control_type="Button")
#未启⽤的按钮
disabled_btn = main_window.child_window(title="清除所有记忆", auto_id="ClearMemoryButton", control_type="Button")
enable_btn.wait("enabled") #---代码执⾏通过
disabled_btn.wait_not("enabled")#---代码执⾏通过

若按钮置灰状态,说明按钮为 disabled 状态,当输入项不为空时,按钮高亮,此时为enabled 状态

ready:表示窗口可见且已启用

import time
from pywinauto import Application# 打开一个计算器
app = Application(backend="uia").connect(process=1136)
# 获取主窗口
main_window = app.window(title="计算器")
main_window.wait("visible")proc = main_window.child_window(title="打开导航", auto_id="TogglePaneButton", control_type="Button")
proc.wait("ready")#等待成功
proc_chid = main_window.child_window(auto_id="PaneTitleTextBlock", control_type="Text")
proc_chid.wait("ready")#等待失败

is_visible() 用于检查元素是否可见,除此之外,is_enabled() 用于检查元素是否启用

active :表示窗口处于活动状态

        需要注意, 'active' 状态指的是窗口是否处于活动状态,需要先操作应用程序使得焦点设置在该窗口上或者配合 set_focus 来使⽤:

from pywinauto import Application# 连接计算机
app = Application(backend="uia").connect(process=1136)
# 获取窗口
win = app.window(title="计算器")
# 获取焦点
win.set_focus()
# 输入9
win.child_window(title="九", auto_id="num9Button",control_type="Button").click_input()
win.wait("active") #等待成功

5.2 wait_until()

等待满足某个条件

wait_until(timeout, retry_interval,func,value=True,op=operator.eq,*args, **kwargs)

部分参数说明:

  • Timeout :超时时间

  • retry_interval :重试时间

  • func :执行的函数

  • value :比较的值

i=0
def work():global ii += 1print("当前i的值为",i)return i# 总共等待10秒,每个一秒执行word函数,等待work返回的结果为5,否则继续往下执⾏ 
wait_until(10,1,work,5)
print("等待通过")

6. 控件的操作

6.1 点击

click_input():模拟鼠标左键单击操作

from pywinauto import Application# 连接记事本
app = Application(backend='uia').connect(process=71696)
# 获取窗口
win = app.window(class_name="Notepad")
win.wait("exists")
#点击文件按钮
win.child_window(title="文件", auto_id="File", control_type="MenuItem").click_input()

right_click_input():模拟鼠标右键单击操作

from pywinauto import Application# 连接记事本
app = Application(backend='uia').connect(process=71696)
# 获取窗口
win = app.window(class_name="Notepad")
win.wait("exists")
win.print_control_identifiers()
# 右击标签页
win.child_window(auto_id="Tabs", control_type="Tab").right_click_input()

double_click_input() :模拟鼠标右键双击操作

from pywinauto import Application# 连接计算器
app = Application(backend='uia').connect(process=1136)
# 获取窗口
win = app.window(title="计算器")
win.wait("exists")#双击按钮8
win.child_window(title="八", auto_id="num8Button",control_type="Button").double_click_input()

6.2 文本

texts():用于获取窗口或控件中的所有⽂本内容,返回⼀个列表,其中每个元素是⼀个字符串,表⽰窗⼝或控 件中的某个⽂本⽚段

获取窗口或控件的标题

from pywinauto import Application# 连接记事本
app = Application(backend='uia').connect(process=29680)
# 获取窗口
win = app.window(class_name="Notepad")
win.wait("exists")
# 获取控件
control_title=win.child_window(title="编辑", auto_id="Edit", control_type="MenuItem")
control_title.wait("exists")
# 打印窗口标题
print(win.texts())
# 打印控件标题
print(control_title.texts())

window_text():⽤于获取窗⼝或控件的主⽂本内容,通常是指窗⼝的标题或主要显⽰的⽂本。它返回⼀个字符串

7. 鼠标操作

在使⽤pywinauto进⾏⾃动化测试时,我们通常会利⽤控件的点击⽅法来实现交互操作。这些⽅法不仅⽀持对控件的直接点击,还允许通过指定coords 参数来实现基于坐标的点击操作。

例如,当我们尝试通过win.double_click_input(coords=(1043, 130)) 来点击SublimeText窗⼝的最⼤化按钮时,虽然语法上没有问题,但这种⽅法可能⽆法完全满⾜我们的需求,尤其是在需要更精确或更灵活的⿏标交互时。

from pywinauto import Application# 连接记事本
app = Application(backend='uia').connect(process=29680)
# 获取窗口
win = app.window(class_name="Notepad")
win.wait("exists")# 点击记事本最大化按钮
win.double_click_input(coords=(763,16))

        为了解决这⼀问题,pywinauto提供了⼀个独⽴的mouse 模块,专⻔⽤于模拟真实⽤⼾的⿏标事 件。这个模块的优势在于,它完全独⽴于控件操作,能够更贴近真实⽤⼾的⾏为模式。通过mouse 模块,我们可以直接在屏幕上指定坐标进行点击、双击、拖动等操作,⽽⽆需依赖控件的层次结构。

mouse模块常见操作:

⽅法功能描述
mouse.click(button='left', coords=(0, 0))单击指定的坐标
mouse.scroll(coords=(0, 0), wheel_dist=1)滚动⿏标滚轮,wheel_dist表⽰滚动的距离,⼤于0是向上滚动,⼩于0是向下 滑动。
mouse.double_click(button='left', coords=(0, 0))双击指定的坐标
mouse.right_click(coords=(0, 0))右键单击指定的坐标
mouse.move(coords=(0, 0))移动鼠标到指定坐标
mouse.wheel_click(coords=(0, 0))鼠标中键单击指定的坐标
mouse.press(button='left', coords=(0, 0))按下鼠标按钮
mouse.release(button='left', coords=(0, 0))释放鼠标按钮

rectangle() :获取元素对应坐标,返回矩形尺⼨,具有top,left,right,bottom属性

mid_point() :获取元素中间位置坐标,返回类型为元组,元组中两个整数分别是X、Y轴的值

rectangle() 和mid_point()使用方式

from pywinauto import Application# 连接记事本
app = Application(backend='uia').connect(process=29680)
# 获取窗口
win = app.window(class_name="Notepad")
win.wait("exists")
# 获取控件
control_title=win.child_window(title="编辑", auto_id="Edit", control_type="MenuItem")
control_title.wait("exists")
# 获取控件的top,left,right,bottom
position=control_title.rectangle()
# 可以通过这种方式,将其打印出来
print("top="f'{position.top}',"left="f'{position.left}',"right="f'{position.right}',"bottom="f'{position.bottom}')
# 获取该控件或窗口的中间坐标
mid=win.rectangle().mid_point()
# 打印窗口中间的坐标
print("x="f"{mid.x}","y="f"{mid.y}")

mouse模块的使用

from pywinauto import Application, mouse# 连接记事本
app = Application(backend='uia').connect(process=29680)
# 获取窗口
win = app.window(class_name="Notepad")
win.wait("exists")
# 获取控件
control_title=win.child_window(title="编辑", auto_id="Edit", control_type="MenuItem")
control_title.wait("exists")# 获取该控件或窗口的中间坐标
mid=control_title.rectangle().mid_point()
# 点击该控件
mouse.click(coords=(mid.x,mid.y))
time.sleep(3)
# 将鼠标移至可以通过鼠标滑动的位置
mouse.scroll(coords=(500,500),wheel_dist=-20)

8. 键盘操作

        在⾃动化测试中,pywinauto提供了强⼤的键盘操作功能,其中keyboard模块是核⼼组件之⼀。 keyboard.send_keys() 是⼀个通⽤的键盘输⼊⽅法,它可以直接将按键序列发送到当前具有焦点的窗⼝。然⽽,在实际的⾃动化场景中,我们通常需要针对特定的控件(如⽂本框、按钮等)进⾏精确的输⼊操作,⽽不是依赖于窗⼝的焦点状态。

from pywinauto.keyboard import send_keys
send_keys("1234567")

        为了满⾜这种需求,pywinauto对键盘输⼊功能进⾏了进⼀步的封装,引⼊了type_keys ⽅法。 type_keys 是控件对象(例如Edit控件或Button控件)的专属⽅法,可以直接作⽤于指定的控件,确保输⼊内容精准⽆误。这种⽅法避免了因焦点切换导致的输⼊错误,特别适合在复杂的⽤⼾界⾯中进⾏⾃动化操作

语法:

type_keys(keys,                     # 要输⼊的键序列,可以是普通字符、特殊键或组合键 pause = None,             # 每次按键后的延迟时间(秒) with_spaces = False,      # 如果为 True,则会在输⼊的字符串中保留空格。 with_newlines = False,    # 如果为 True,则会在输⼊的字符串中保留换⾏符。  
)

向当前焦点窗⼝⾃动键⼊键或发送⽂本。

8.1 输入文本
  • 直接输⼊⽂本(⽀持Unicode字符):

from pywinauto import Application, mouse# 连接记事本
app = Application(backend='uia').connect(process=75580)
# 获取窗口
win = app.window(class_name="Notepad")
win.wait("exists")#输⼊⽂本内容
win.type_keys("------type_keys------")
#保留换⾏符
win.type_keys("------type_keys------\n",with_newlines=True)
#保留空格
win.type_keys(" -----type keys----\n",with_spaces=True,with_newlines=True)
#延迟输⼊,避免输⼊过快导致内容不完整
win.type_keys("⼀⼆三四五六七",with_spaces=True)

8.2 按键输入
  • 使⽤{VK_CODE} 格式表⽰虚拟键码,例如:

按键代码
Enter{ENTER}
Tab{TAB}
Backspace{BACKSPACE}
Esc{ESC}
⽅向键{UP} ,{DOWN} ,{LEFT} ,{RIGHT}
F1-F9{F1} - {F9}
Shift+
Ctrl^
Alt%

例如:

import time
from pywinauto import Application, mouse# 连接记事本
app = Application(backend='uia').connect(process=75580)
# 获取窗口
win = app.window(class_name="Notepad")
win.wait("exists")#发送⽂本和回⻋
win.type_keys("Hello World{ENTER}",with_spaces=True)
# +a==Shift+a==A
win.type_keys("+a你好+a,+a大帅哥+a{ENTER}",with_spaces=True)
# 全选和复制
win.type_keys("^a^c",with_spaces=True)
# 在中间位置点一下,重置光标的位置
mid=win.rectangle().mid_point()
mouse.click(coords=(mid.x,mid.y))
# 粘贴
win.type_keys("^v",with_spaces=True)

指定重复次数和转义特殊字符

  • 可以为特殊键指定重复计数。 {ENTER 2} 表⽰按两次Enter键

  • 使⽤{} 包裹特殊字符(如{+} ,{%} ,{^} )以避免被识别为修饰符

from pywinauto import Application, mouse# 连接记事本
app = Application(backend='uia').connect(process=75580)
# 获取窗口
win = app.window(class_name="Notepad")
win.wait("exists")# 指定重复次数
win.type_keys("Hello World{ENTER 5}",with_spaces=True)
win.type_keys("+a你好+a,+a大帅哥+a{ENTER}",with_spaces=True)
# 转义特殊字符
# win.type_keys("1+2=3") # 错误:`+` 会被识别为 Shift
win.type_keys("1{+}2=3") # 正确

9. 菜单控件的操作

  • items():返回对话框的菜单项,如果没有菜单项,则返回空列表

  • item_by_index(idx):查找索引指定的菜单项,idx :索引,从0开始

from pywinauto import Application# 连接VS code2022
app = Application(backend='uia').connect(process=18976)
# 获取窗口
win = app.window(class_name="Window")
win.wait("exists")# 定位菜单栏
menu=win.child_window(title="菜单栏", auto_id="MenuBar", control_type="MenuBar")
# 返回并打印菜单项
print(menu.items())
# 查找索引指定的菜单项,从0开始
print(menu.item_by_index(0))
print(menu.item_by_index(1))

item_by_path()

item_by_path(path, exact=False):⽤户查找路径指定的菜单项

  • path :⽤于指定要选择的菜单项路径。

  • exact :设置为True,则要求菜单项名称与路径中的名称完全匹配;如果为False,则允许模糊匹配路径可以是“MenuItem->MenuItem->MenuItem...”形式的字符串,其中每个MenuItem是菜单该 级别的项⽬⽂本。

from pywinauto import Application# 连接VS code2022
app = Application(backend='uia').connect(process=18976)
# 获取窗口
win = app.window(class_name="Window")
win.wait("exists")# 定位菜单栏
menu=win.child_window(title="菜单栏", auto_id="MenuBar", control_type="MenuBar")# # 方法一 通过item_by_path
# # menu.item_by_path("文件(F)->新建(N)->项目(P)...").click_input()
menu.item_by_path("文件(F)->main.cpp另存为(A)...").click_input()
# 方法二 通过按键
file=menu. child_window(title="文件", control_type="MenuItem").click_input()
win.type_keys("A")

空格并不重要,所以你也可以写...

                File -> Export -> Export As PNG

menu_select()

menu_select(path, exact=False):⽤户查找路径指定的菜单项

  • path :⽤于指定要选择的菜单项路径。

  • exact :设置为True,则要求菜单项名称与路径中的名称完全匹配;如果为False,则允许模糊匹配 注意, menu_select() 的使⽤和上⾯有区别,使⽤ menu_select() 的场景下,通常⾄少有两个 菜单栏:“系统”和“应⽤程序”系统菜单栏是⼀个标准的窗⼝菜单,包含以下项⽬:“还 原”、“移动”、“⼤⼩”、“最⼩化”等。此菜单栏通常有⼀个“标题栏”控件作为⽗级。应⽤程序菜单栏通常是我们要找的。在⼤多数情况下,它的⽗级是对话框本⾝,因此可以在对话框的直接⼦ 级中找到它。

10. 列表控件的操作

  • get_items():获取列表视图中的所有项⽬。

  • item_count():列表视图中的项数。

  • get_item():返回列表视图中的指定项⽬。row :可以是⾏的索引

⽰例:打印⽂件资源管理列表项

from pywinauto import Application# 连接文件资源管理器
app = Application(backend='uia').connect(process=9904)
# 获取窗口
win = app.window(class_name="CabinetWClass")
win.wait("visible")
# 获取list表的定位,最近访问
list=win.child_window(auto_id="HomeListView", control_type="List")
# 打印最近访问列表
print("items:",list.get_items())
#打印列表项数量
print("items:",list.item_count())
#获取列表中第⼀项
print("items:",list.get_item(row=0))

五、自动化测试场景示例

给抖音自动点赞

# 连接抖音
app = Application(backend='uia').connect(process=10072)
# 获取窗口
win = app.window(title="抖音")
win.wait("exists")
# win.print_control_identifiers()for i in range (0,3):# 定位窗口中间位置mid=win.rectangle().mid_point()# 双击该位置mouse.double_click(button='left', coords=(mid.x, mid.y))time.sleep(1)# 滑动该位置mouse.scroll(coords=(mid.x, mid.y), wheel_dist=-500)
http://www.dtcms.com/a/436048.html

相关文章:

  • 杭州网站设计费用app软件下载入口
  • 网站建设php教程建设一个好的网站
  • 遵义网站建设找工作百安居装修口碑怎么样
  • 用别人的网站视频做app网站建设文字设计
  • 网站建设推广兼职地推一手项目平台
  • 网站建设和安全管理制度html5制作网页的代码
  • C++类和对象(1)
  • 嵌入式开发学习日志32——stm32之PWM
  • 数据结构 之 【图的最短路径】(Dijstra、BellmanFord、FloydWarShall算法实现)
  • 时序数据库高基数问题(一):当数据标签太多时会发生什么
  • 东莞市企业网站制作企业关键词推广优化排名品牌
  • 个人网站免费搭建软文标题和内容
  • 普洱高端网站建设价格燕郊房价2023年最新房价走势
  • 怎么做二维码微信扫后直到网站合肥网站排名提升
  • 如何办网站 论坛网站一定要公司吗
  • 主流网站开发平台新媒体运营需要哪些技能
  • 江门网站php网站开发遇到的问题
  • 做韦恩图网站建网站如果不买域名别人能不能访问
  • 如何让订阅号菜单做微网站安徽鲁班建设集团网站
  • 51——DS18B20
  • 网站建设安全协议wordpress 添加插件
  • 区总工会加强网站意识形态建设深圳网络科技有限公司简介
  • 【HTB】Season9 Imagery Walkthrough
  • 异常与c++11中的noexcept【c++】
  • 免费网站制作效果重庆建设施工安全信息网官网
  • 网站设计报价是多少钱网站建设项目计划书
  • Python语言中的应用程序接口(API):本质探析、高级应用与实践范式
  • 小学生做网站下载谷歌浏览器
  • 淄博网站制作高端营销手表网站妨水
  • Spring Boot 常用注解分类整理(含用法示例)