前言
上一篇文章地址:
pywinauto:Windows桌面应用自动化测试(七)-CSDN博客
下一篇文章地址:
暂无
一、实战常用方法
1、批量筛选元素
如果元素的一些属性具备部分相分,那该如何批量获取这些元素呢?如图,假设我想设置IP地址等信息,而每个输入都有一部分相同的情况,当我一键匹配后会有部分输入为空,我将判断为空时输入数值1,该如何做呢?
假设元素的auto_id包含
"FormNetworkAdapterConfigure.frame_2.groupBoxStaticIp.frame_5" 字符串,将该字符串赋值给
auto_id_prefix这个变量,那么我们可以通过方法
descendants()获取所有元素,再再这些元素中筛选出指定元素,并操作这些元素。
def add_ip_to_auto_match(self):
'''补充一键匹配的ip'''
ip_set_window = self._connect_ip_set()
# 过滤包含指定 auto_id 前缀的子窗口
all_windows = ip_set_window.descendants()
auto_id_prefix = "FormNetworkAdapterConfigure.frame_2.groupBoxStaticIp.frame_5"
matching_windows = [window for window in all_windows if window.automation_id().startswith(auto_id_prefix)]
# # 输出匹配的窗口信息
# for window in matching_windows:
# print(
# f"Title: {window.window_text()}, Auto ID: {window.automation_id()}, Control Type: {window._control_types}")
# 输出匹配的元素
StaticIp_list = []
for window in matching_windows:
if auto_id_prefix in window.automation_id() and "frameIP.txtIP" in window.automation_id():
print(window.automation_id())
StaticIp_list.append(window.automation_id())
# 为空时输入数字1
for StaticIp in StaticIp_list:
wt = ip_set_window.child_window(auto_id=StaticIp).window_text()
if wt == "":
ip_set_window.child_window(auto_id=StaticIp).set_text(1)
print(wt)
这个示例代码中,我们首先使用 descendants
获取所有子窗口,然后使用 Python 的列表解析来过滤出 auto_id
以 FormNetworkAdapterConfigure.frame_2.groupBoxStaticIp.frame_5
开头的所有窗口。这样可以确保获取到所有符合条件的窗口。
(1)代码的功能描述
该方法通过 _connect_ip_set 连接到一个特定的窗口 ip_set_window。
使用 descendants 方法获取所有子窗口,并根据 auto_id 过滤出特定的窗口。
将符合条件的窗口的 automation_id 存储到 StaticIp_list 列表中。
遍历 StaticIp_list,检查每个窗口的文本是否为空,如果为空,则设置为 1,并打印窗口文本。
(2)关键方法解释
descendants(): 获取窗口的所有子窗口。
automation_id(): 获取窗口的自动化 ID。
child_window(auto_id=...): 根据自动化 ID 查找子窗口。
window_text(): 获取窗口的文本。
set_text(): 设置窗口的文本。
2、使用child_window有多个对象符合
此时可以通过上述的descendants()来替换。
假设 list_items = combo_box.child_window(control_type="ListItem") 获取到了三个对象,那么就给出报错信息:
pywinauto.findwindows.ElementAmbiguousError: There are 3 elements that match the criteria {'control_type': 'ListItem', 'top_level_only': False, 'parent': <uia_element_info.UIAElementInfo - '', NetworkAdapterComboBox, None>, 'backend': 'uia'}
此时,可以通过参数found_index指定某个元素,但要获取三个元素时,可以通过descendants()来替换:
# 获取 ComboBox 中所有的 ListItem 对象
list_items = combo_box.descendants(control_type="ListItem")
# 打印每个 ListItem 的信息
for item in list_items:
print(item.window_text())
# 也可以访问每个 ListItem 的其他属性或方法
# 例如,选择每个 ListItem
for item in list_items:
item.select()
print(f"Selected: {item.window_text()}")
3、下拉选择框的操作方式
item.select()
是 pywinauto
库中的方法,用于选择一个 ListItem
对象。它的作用是模拟用户点击该项,以将其选中。在用户界面中,这相当于在下拉列表中点击某一项来选择它。
在上个例子中,我们调用了item.select()方法去选择元素,通常也会触发点击事件来选中该项,但也有例外。此时,就需要点击才能被选中。
4、子窗口界面遮住父窗口时能连父窗口么
当使用 pywinauto
进行自动化测试时,如果子窗口(如对话框)遮住了父窗口,通常仍然可以与父窗口进行交互。pywinauto
基于控件树和窗口句柄的方式来操作窗口和控件,因此它并不完全依赖于窗口的视觉呈现(即使窗口被遮挡,仍然可以通过它的句柄进行操作)。
5、列表对象的操作方式
列表对象的操作跟表格对象的操作有点相似,但有必要说明一下:
(1)列表对象(List Object)
用途: 列表对象通常用于显示单列数据项的集合,每个数据项通常是一行文本或一个简单的项。列表对象更像是一个一维的数据容器。
常见控件: `ListBox`, `ListView`。
结构: 列表对象的每个项(`ListItem`)通常只包含一个文本字段,所有的项都排列在一个垂直或水平方向上。
操作:
- 可以选择、双击、右键点击、获取文本等操作。
- 通过 `children()` 获取所有列表项,通常是 `ListItemWrapper` 对象的集合。
示例:
list_control = window.child_window(control_type="List")
list_items = list_control.children(control_type="ListItem")
使用场景: 用于简单的数据展示,比如菜单项列表、文件列表等。
(2)表格对象(Table Object)
用途: 表格对象用于显示多列数据项的集合,每个数据项通常是一个二维的数据表格,包括多行和多列。表格对象更像是一个二维的数据容器。
常见控件: `DataGrid`, `Table`, `ListView`(在具有多列时,也可以作为表格处理)。
结构: 表格对象的每一行(`Row` 或 `TableItem`)由多个列组成,每列可以包含不同类型的数据(文本、图像、复选框等)。
操作:
- 可以选择特定单元格、双击单元格、获取单元格内容、排序列等。
- 通过 `children()` 或者 `item_by()` 获取表格行或单元格,通常是 `TableItemWrapper` 或 `TableCellWrapper` 对象。
示例:
table_control = window.child_window(control_type="Table")
rows = table_control.children(control_type="DataItem") # 每一行作为一个 DataItem
cell = table_control.cell(row=0, column=1) # 获取特定单元格
使用场景: 用于复杂的数据展示,比如电子表格、数据库结果显示、用户表格数据输入等。
主要区别:
数据结构: 列表对象是一维数据结构,表格对象是二维数据结构。
显示形式: 列表对象通常以单列形式展示,表格对象以多列形式展示。
操作复杂性: 表格对象的操作更为复杂,因为需要处理多列、多行数据,而列表对象则只需处理单列数据。
(3)简单用法
假设列表元素为list_items ,以下函数实现了依次点击找到的列表元素:
def click_scheme(self):
list_items = self.scheme_win.child_window(auto_id="MainForm.widget_client.viScanner.qt_tabwidget_stackedwidget.Equipment.ProjectManagePage.widget_content.listWidget_items", control_type="List").children(control_type="ListItem")
for item in list_items:
item.click_input()
(4)列表中内嵌的信息是否可以获取
很遗憾,不行。但是可以通过OCR的方式间接获取,这就涉及到保存图片,可以通过capture_as_image()方法获取列表元素的图片,再对图片进行分析。
from PIL import ImageGrab, Image
# 另一种方法
# rect = item.rectangle()
# image = ImageGrab.grab(bbox=(rect.left, rect.top, rect.right, rect.bottom))
# 常用方法
image = item.capture_as_image()
# image.show() # 显示截图
image.save("element_screenshot.png") # 保存截图
个人在使用的OCR给大家推荐一下:
pip install paddleocr
pip install paddlepaddle
PaddlePaddle 是由百度开发的一个端到端的开源深度学习平台,类似于 TensorFlow 或 PyTorch。
PaddleOCR 是基于 PaddlePaddle 的一个光学字符识别(OCR)库,专注于文本检测、文本识别和表格识别等任务。
换句话说,PaddleOCR 是构建在 PaddlePaddle 框架之上的一个应用库,利用 PaddlePaddle 提供的底层深度学习能力,专门处理 OCR 任务。
OCR用法:
from paddleocr import PaddleOCR, draw_ocr
ocr = PaddleOCR(use_angle_cls=True, lang="ch")
img_path = r"D:\软件\传统安装\python\mystudy\pages\element_screenshot.png"
result = ocr.ocr(img_path, cls=True)
for block in result:
for line in block:
text = line[1][0] # 提取文本内容
print(text)
有时候空格会被忽略,这个好像也不是什么大事,咋们也直接忽略就好。如果要识别O空格,可以查阅一些资料,比如下面的链接: