pywinauto桌面端自动化

1.自动化流程

1.在handles和pageObject中封装方法

1.把所有元素都先定义为None,这样只需要传输唯一元素即可,不需要传递所有元素,减少代码的冗余

封装元素定位方法:

    def locate_element(
            self,
            class_name=None,
            class_name_re=None,
            title=None,
            title_re=None,
            control_type=None,
            best_match=None,
            auto_id=None,
            found_index=0):
        """
        封装所有pywinauto定位元素的方法\n
        class_name=None, # 类名\n
        class_name_re=None, # 正则匹配类名\n
        title=None, # 控件的标题文字,对应inspect中Name字段\n
        title_re=None, # 正则匹配文字\n
        control_type=None, # 控件类型,inspect界面LocalizedControlType字段的英文名\n
        best_match=None, #\n
        auto_id=None, # 这个也是固定的可以用,inspect界面AutomationId字段,但是很多控件没有这个属性
        """
        try:
            element = self.driver.child_window(class_name=class_name,
                                               class_name_re=class_name_re,
                                               title=title,
                                               title_re=title_re,
                                               control_type=control_type,
                                               best_match=best_match,
                                               auto_id=auto_id,
                                               found_index=found_index).wait('visible')
            element.draw_outline(colour="green", thickness=5)
        except Exception as e:
            element = None
            self.log.info(e)
            self.log.error(inspect.currentframe().f_back.f_code.co_name + " 元素定位输入有误")
        return element

2.通过调用封装的元素定位方法,进行调用

一个测试用例示例:

# 下述文件应该放置在页面对象定义中,封装了页面元素的定位和操作方法,如:pageObject目录下
# 控件定位
def clear_machine_loc(self):
    """
    获取清机元素
    """
    return self.locate_element(title='清机')
def clear_machine_yes_loc(self):
    """
    获取清机确定元素
    """
    return self.locate_element(auto_id='PageBase.widgetMain.CashierWidget.SFMessageForm.btnOk')
def text_clear_machine_tips_loc(self):
    """
    获取清机提示文本
    """
    return self.clear_machine_tips_loc().window_text()
def clear_machine_no_loc(self):
    """
    获取清机取消元素
    """
    return self.locate_element(auto_id='PageBase.widgetMain.CashierWidget.SFMessageForm.btnCancel')



# 下述文件应该放置在页面操作处理文件夹中 如:handlers目录下
# 调用控件方法,执行操作
def click_clear_machine_loc(self):
    """
    点击清机按钮
    """
    self.clear_machine_loc().click_input()
def click_clear_machine_yes_lco(self):
    """
    点击确定按钮
    """
self.clear_machine_yes_loc().click_input()
def text_clear_machine_tips_loc(self):
    """
    获取清机提示文本
    """
    return self.clear_machine_tips_loc().window_text()
def click_clear_machine_no_lco(self):
    """
    点击取消按钮
    """
    self.clear_machine_no_loc().click_input()

#下述文件应该放置在测试用例中,将手动操作的步骤代码化 如:testCase目录下
# 执行测试用例
@allure.story("操作清机") # 标记当前测试用例对应的用户故事或测试场景
@allure.title("清机_确认") # 当前测试用例在报告中显示的标题名称
@allure.description("该用例检查用户确认清机操作") # 为测试用例添加描述信息,说明该用例的测试目的
# 为测试用例添加一个可点击的外部链接,通常指向测试管理系统中的手工用例
@allure.testcase(
    "手工用例url地址",
    name="点击,跳转到对应用例的链接地址")
# 标明当前用例的执行优先级
@pytest.mark.p0
def test_clear_machine_forward(self):
    # 步骤1:点击清机按钮
    with allure.step('点击清机按钮'):
        self.mph.click_clear_machine_loc()
    # 记录当前时间,用于后续校验
    current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    # 步骤2:点击确定按钮
    with allure.step('点击确定'):
        self.mph.click_clear_machine_yes_lco()
    # 步骤3:再次点击清机按钮
    with allure.step('再次点击清机按钮'):
        self.mph.click_clear_machine_loc()
    # 步骤4:校验清机是否成功
    with allure.step('校验是否已清机成功'):
        assert current_time in self.mph.text_clear_machine_tips_loc()
    # 最后一步:点击取消按钮,退出清机界面
    self.mph.click_clear_machine_no_lco()

3.执行断言,验证输出的结果

4.输出测试结果,通过或者失败

2.所有控件类型:

Button(按钮)
Calendar(日历)
CheckBox(复选框)
ComboBox(组合框 / 下拉框)
Custom(自定义控件)
DataGrid(数据网格)
DatePicker(日期选择器)
Dialog(对话框)
Document(文档控件)
Edit(编辑框 / 文本框)
GroupBox(组框)
Header(头部控件)
Hyperlink(超链接)
Image(图像控件)
Label(标签 / 静态文本)
ListBox(列表框)
ListView(列表视图)
Menu(菜单)
MenuBar(菜单栏)
MenuItem(菜单项)
Pane(窗格)
PopupMenu(弹出菜单)
ProgressBar(进度条)
RadioButton(单选框)
ScrollBar(滚动条)
Separator(分隔符)
Slider(滑块)
Spinner(微调器 / 数字增减控件)
SplitButton(分割按钮)
StatusBar(状态栏)
TabControl(选项卡控件)
TabItem(选项卡项)
Table(表格)
Text(文本控件)
Thumb(滑块拇指)
TitleBar(标题栏)
ToolBar(工具栏)
ToolTip(工具提示)
Tree(树状视图)
TreeItem(树节点)
Window(窗口)

3.鼠标操作 

click() #单击鼠标某个键
double_click() #双击鼠标某个键
right_click() #单击鼠标右键
move() #移动鼠标
press() #按下鼠标
release() #放开鼠标
scroll() #滚动鼠标滚轮
wheel_click() #单击鼠标滚轮

4.遍历展示所有界面元素 

from pywinauto.findwindows import find_elements

els=find_elements(backend='uia')
for el in els:
    print(el)

5.打印的内容 

uia_element_info.UIAElementInfo - '', SoPY_Status
uia_element_info.UIAElementInfo - '任务栏', Shell_TrayWnd
uia_element_info.UIAElementInfo - 'WeMail', Qt51517QWindowToolSaveBits
uia_element_info.UIAElementInfo - 'test.py - webuiauto - Visual Studio Code', Chrome_WidgetWin_1
uia_element_info.UIAElementInfo - 'linux命令', Chrome_WidgetWin_1
uia_element_info.UIAElementInfo - 'ProcessExplorer', CabinetWClass

6.连接并打印窗口所有元素 

# 连接窗口
app = Application(backend='uia').connect(title="linux命令")
# 定位到linux命令窗口
dlg = app.window(title="linux命令")

# 打印窗口的所有元素
dlg.print_control_identifiers()

7.以fiddler为例 

from pywinauto.application import Application
from pywinauto.findwindows import find_elements
import time

#获取当前所有窗口
els = find_elements(backend='uia')
print(els)

# 打开/链接fiddler工具
# app = Application(backend='uia').start('C:/Program Files (x86)/Fiddler2/Fiddler.exe')
app = Application(backend='uia').connect(title_re='Progress Telerik Fiddler web Debugger')

#获取窗口
dlg = app.window(title_re='Progress Telerik Fiddler web Debugger')

#点击停止抓包
# dlg.child_window(title_re='.*停止.*', control_type="Button").click()
el = dlg.child_window(best_match='Capturing')
el.click_input()

# 点击导出数据包
dlg.menu_select('File->Export Sessions')#菜单定位只能定位下级,无法定位下下级
# 子菜单选择,选择所有数据包
menu_item = app.window(best_match='All Sessions...')
menu_item.select()

#选择数据包格式
com = dlg.child_window(best_match='ComboBox')
com.click_input()
com_list = dlg.child_window(best_match='ComboBox')
com_list.click_input()

#点击next  
com_list = dlg.child_window(best_match='Next')
com_list.click_input()

#文件对话框输入文件名
dlg.child_window(best_match='Text').set_text('flddler文件')

#点击保存
dlg.child_window(title='保存(S)').click_input()

8.PID定位未打开的软件,执行操作 

import logging
from pywinauto import Application
import time
# 设置日志格式
logging.basicConfig(level=logging.INFO, format='[%(asctime)s] %(levelname)s: %(message)s')
# 启动语雀应用
app = Application(backend='uia').start(r"D:\yuque\语雀.exe")

# 等待应用启动
time.sleep(5)

# 获取 ProcessId
pid = app.process
print(f"语雀PID: {pid}")

# 通过 ProcessId 连接主窗口
app = Application(backend='uia').connect(process=pid)
main_window = app.window(title_re=".*py.*", control_type="Pane") # 需要一个关键词去做定位
main_window.wait("exists enabled visible", timeout=10)  # 确保窗口可见可用
print("[成功] 已找到语雀主窗口")

# 定位并点击“fiddler使用说明”控件
try:
    fiddler_link = main_window.child_window(title_re=".*fiddler使用说明.*", control_type="Hyperlink")
    fiddler_link.wait("exists enabled visible", timeout=5)
    fiddler_link.invoke()
    print("[成功] 已点击“fiddler使用说明”控件")
    time.sleep(3)
except Exception as e:
    print(f"[错误] 无法点击“fiddler使用说明”控件: {e}")

# 定位并点击“sql”控件
try:
    use_case_link = main_window.child_window(title_re=".*sql.*", control_type="Hyperlink")
    print("[成功] 已找到“sql”控件")
    use_case_link.wait("exists enabled visible", timeout=5)
    use_case_link.invoke()
    print("[成功] 已点击“sql”控件")
except Exception as e:
    print(f"[错误] 无法点击“sql”控件: {e}")

9.通过任务管理器找到对应软件的handle进行连接操作

import logging
from pywinauto.findwindows import find_elements
from pywinauto.application import Application
import psutil

# 设置日志格式
logging.basicConfig(level=logging.INFO, format='[%(asctime)s] %(levelname)s: %(message)s')

def find_window_by_process_name(process_name, backend='uia'):
    """
    通过进程名(如 语雀.exe)查找窗口,适用于 Electron 应用
    """
    windows = find_elements(backend=backend)
    for win in windows:
        try:
            p = psutil.Process(win.process_id)
            if p.name() == process_name:
                return win
        except psutil.NoSuchProcess:
            continue
    return None

# 主流程,此处填写需要连接的进程名
win_info = find_window_by_process_name('语雀.exe', backend='uia')

if win_info:
    print(f"窗口名称: {win_info.name}")
    print(f"PID: {win_info.process_id}")
    print(f"Handle: {win_info.handle}")

    # 连接窗口
    app = Application(backend='uia').connect(handle=win_info.handle)
    main_window = app.window(handle=win_info.handle)
    main_window.set_focus()
    main_window.print_control_identifiers()

    print("[成功] 已连接到语雀窗口")
else:
    raise Exception("未找到语雀窗口,请确认语雀已启动")
# 定位并点击“fiddler”控件
try:
    fiddler_link = main_window.child_window(title_re=".*fiddler.*", control_type="Hyperlink")
    # link = dlg.child_window(title_re=".*fiddler.*", control_type="Hyperlink")
    print("[成功] 已找到“fiddler”控件")
    fiddler_link.wait("exists enabled visible", timeout=5)
    print("[成功] 已等待“fiddler”控件")
    # fiddler_link.click_input()
    fiddler_link.invoke()
    print("[成功] 已点击“fiddler”控件")
except Exception as e:
    print(f"[错误] 无法点击“fiddler”控件: {e}")

# 定位并点击“sql”控件
try:
    use_case_link = main_window.child_window(title_re=".*sql.*", control_type="Hyperlink")
    use_case_link.wait("exists enabled visible", timeout=5)
    use_case_link.invoke()
    print("[成功] 已点击“sql”控件")
except Exception as e:
    print(f"[错误] 无法点击“sql”控件: {e}")




 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值