window GUI 自动化 ——001

269 阅读7分钟

window GUI 自动化

window GUI (Graphical User Interface) 图形用户界面

自动化 通过自动化脚本代码 实现对GUI程序 的功能进行测试 或者 任务脚本编写。

基于python 自动化 (windows platform)

  1. 安装对应的包 terminal 输入command pywinauto 0.6.8 (版本选择)

    pip install pywinauto -i https://pypi.tuna.tsinghua.edu.cn/simple

  2. terminal 查看版本信息

    pip list | findstr pywinauto

  3. 结果 image.png

windowauto 辅助工具

github 上相关window inspect tools

如何配置guihub 下载加速 image.png

查看方式

UI Automation 方式下 可以看到更多的控件元素信息

insights 工具

所有工具大同小异 都是辅助工具内容 对于相关的内容进行处理操作 主要关注点

title 、class_name、 handle_id、 process_id

image.png

灵活使用 pywinauto 中的窗口打印属性知识


from pywinauto import Application

app = Application(backend="uia").start("calc.exe")
dlg = Desktop(backend="uia")["计算器"]
dlg.type_keys("2*3=")

dlg.print_control_identifiers(filename="calculator.ini")

导出的calculator.ini

  1. 编码格式 window GBK
  2. 导出形式为树形结构内容
Control Identifiers:

Dialog - '计算器'    (L6, T61, R342, B602)
['Dialog', '计算器', '计算器Dialog', 'Dialog0', 'Dialog1', '计算器0', '计算器1', '计算器Dialog0', '计算器Dialog1']
child_window(title="计算器", control_type="Window")
   | 
   | Dialog - '计算器'    (L14, T62, R334, B94)
   | ['Dialog2', '计算器2', '计算器Dialog2']
   | child_window(title="计算器", auto_id="TitleBar", control_type="Window")
   |    | 
   |    | Menu - '系统'    (L0, T0, R0, B0)
   |    | ['系统', 'Menu', '系统Menu', '系统0', '系统1']
   |    | child_window(title="系统", auto_id="SystemMenuBar", control_type="MenuBar")
   |    |    | 
   |    |    | MenuItem - '系统'    (L0, T0, R0, B0)
   |    |    | ['MenuItem', '系统2', '系统MenuItem']
   |    |    | child_window(title="系统", control_type="MenuItem")
   |    | 
   |    | Button - '最小化 计算器'    (L196, T62, R242, B94)
   |    | ['Button', '最小化 计算器', '最小化 计算器Button', 'Button0', 'Button1']
   |    | child_window(title="最小化 计算器", auto_id="Minimize", control_type="Button")
   |    | 
   |    | Button - '使 计算器 最大化'    (L242, T62, R288, B94)
   |    | ['Button2', '使 计算器 最大化', '使 计算器 最大化Button']
   |    | child_window(title="使 计算器 最大化", auto_id="Maximize", control_type="Button")
   |    | 
   |    | Button - '关闭 计算器'    (L288, T62, R334, B94)
   |    | ['Button3', '关闭 计算器Button', '关闭 计算器']
   |    | child_window(title="关闭 计算器", auto_id="Close", control_type="Button")
   | 
   | Dialog - '计算器'    (L14, T62, R334, B594)
   | ['Dialog3', '计算器3', '计算器Dialog3']
   | child_window(title="计算器", control_type="Window")
   |    | 
   |    | Static - '计算器'    (L26, T70, R62, B86)
   |    | ['Static', '计算器Static', '计算器4', 'Static0', 'Static1']
   |    | child_window(title="计算器", auto_id="AppName", control_type="Text")
   |    | 
   |    | Button - '打开导航'    (L14, T94, R54, B134)
   |    | ['Button4', '打开导航Button', '打开导航']
   |    | child_window(title="打开导航", auto_id="TogglePaneButton", control_type="Button")
   |    | 
   |    | Static - '标准'    (L66, T100, R106, B127)
   |    | ['Static2', '标准', '标准Static']
   |    | child_window(title="标准", auto_id="Header", control_type="Text")
   |    | 
   |    | GroupBox - ''    (L14, T94, R334, B590)
   |    | ['GroupBox', '计算器GroupBox', 'GroupBox0', 'GroupBox1']
   |    |    | 
   |    |    | Static - '显示为 0'    (L14, T155, R334, B232)
   |    |    | ['Static3', '显示为 0', '显示为 0Static']
   |    |    | child_window(title="显示为 0", auto_id="CalculatorResults", control_type="Text")
   |    |    | 
   |    |    | Static - '表达式为 '    (L0, T0, R0, B0)
   |    |    | ['Static4', '表达式为 Static', '表达式为 ']
   |    |    | child_window(title="表达式为 ", auto_id="CalculatorExpression", control_type="Text")
   |    |    | 
   |    |    | Button - '打开历史记录浮出控件'    (L294, T94, R334, B134)
   |    |    | ['Button5', '打开历史记录浮出控件', '打开历史记录浮出控件Button']
   |    |    | child_window(title="打开历史记录浮出控件", auto_id="HistoryButton", control_type="Button")
   |    |    | 
   |    |    | GroupBox - '内存控件'    (L18, T233, R330, B265)
   |    |    | ['GroupBox2', '内存控件GroupBox', '内存控件']
   |    |    | child_window(title="内存控件", auto_id="MemoryPanel", control_type="Group")
   |    |    |    | 
   |    |    |    | Button - '清除所有内存'    (L18, T233, R68, B265)
   |    |    |    | ['Button6', '清除所有内存Button', '清除所有内存']
   |    |    |    | child_window(title="清除所有内存", auto_id="ClearMemoryButton", control_type="Button")
   |    |    |    | 
   |    |    |    | Button - '内存重新调用'    (L70, T233, R120, B265)
   |    |    |    | ['Button7', '内存重新调用', '内存重新调用Button']
   |    |    |    | child_window(title="内存重新调用", auto_id="MemRecall", control_type="Button")
   |    |    |    | 
   |    |    |    | Button - '内存添加'    (L122, T233, R172, B265)
   |    |    |    | ['Button8', '内存添加Button', '内存添加']
   |    |    |    | child_window(title="内存添加", auto_id="MemPlus", control_type="Button")
   |    |    |    | 
   |    |    |    | Button - '内存减少'    (L174, T233, R224, B265)
   |    |    |    | ['Button9', '内存减少', '内存减少Button']
   |    |    |    | child_window(title="内存减少", auto_id="MemMinus", control_type="Button")
   |    |    |    | 
   |    |    |    | Button - '内存存储'    (L226, T233, R277, B265)
   |    |    |    | ['Button10', '内存存储Button', '内存存储']
   |    |    |    | child_window(title="内存存储", auto_id="memButton", control_type="Button")
   |    |    |    | 
   |    |    |    | Button - '打开内存浮出控件'    (L280, T233, R330, B265)
   |    |    |    | ['Button11', '打开内存浮出控件Button', '打开内存浮出控件']
   |    |    |    | child_window(title="打开内存浮出控件", auto_id="MemoryButton", control_type="Button")
   |    |    | 
   |    |    | GroupBox - '标准函数'    (L18, T267, R330, B319)
   |    |    | ['GroupBox3', '标准函数GroupBox', '标准函数']
   |    |    | child_window(title="标准函数", auto_id="StandardFunctions", control_type="Group")
   |    |    |    | 
   |    |    |    | Button - '百分比'    (L18, T267, R94, B319)
   |    |    |    | ['Button12', '百分比Button', '百分比']
   |    |    |    | child_window(title="百分比", auto_id="percentButton", control_type="Button")
   |    |    |    | 
   |    |    |    | Button - '平方根'    (L96, T267, R172, B319)
   |    |    |    | ['Button13', '平方根Button', '平方根']
   |    |    |    | child_window(title="平方根", auto_id="squareRootButton", control_type="Button")
   |    |    |    | 
   |    |    |    | Button - '平方'    (L175, T267, R251, B319)
   |    |    |    | ['Button14', '平方Button', '平方']
   |    |    |    | child_window(title="平方", auto_id="xpower2Button", control_type="Button")
   |    |    |    | 
   |    |    |    | Button - '倒数'    (L253, T267, R329, B319)
   |    |    |    | ['Button15', '倒数', '倒数Button']
   |    |    |    | child_window(title="倒数", auto_id="invertButton", control_type="Button")
   |    |    | 
   |    |    | GroupBox - '标准运算符'    (L253, T321, R329, B589)
   |    |    | ['GroupBox4', '标准运算符GroupBox', '标准运算符']
   |    |    | child_window(title="标准运算符", auto_id="StandardOperators", control_type="Group")
   |    |    |    | 
   |    |    |    | Button - '除以'    (L253, T321, R329, B373)
   |    |    |    | ['Button16', '除以', '除以Button']
   |    |    |    | child_window(title="除以", auto_id="divideButton", control_type="Button")
   |    |    |    | 
   |    |    |    | Button - '乘以'    (L253, T375, R329, B427)
   |    |    |    | ['Button17', '乘以Button', '乘以']
   |    |    |    | child_window(title="乘以", auto_id="multiplyButton", control_type="Button")
   |    |    |    | 
   |    |    |    | Button - '减'    (L253, T429, R329, B481)
   |    |    |    | ['Button18', '减', '减Button']
   |    |    |    | child_window(title="减", auto_id="minusButton", control_type="Button")
   |    |    |    | 
   |    |    |    | Button - '加'    (L253, T483, R329, B535)
   |    |    |    | ['Button19', '加', '加Button']
   |    |    |    | child_window(title="加", auto_id="plusButton", control_type="Button")
   |    |    |    | 
   |    |    |    | Button - '等于'    (L253, T537, R329, B589)
   |    |    |    | ['Button20', '等于Button', '等于']
   |    |    |    | child_window(title="等于", auto_id="equalButton", control_type="Button")
   |    |    | 
   |    |    | GroupBox - '显示控件'    (L18, T321, R251, B373)
   |    |    | ['GroupBox5', '显示控件GroupBox', '显示控件']
   |    |    | child_window(title="显示控件", auto_id="DisplayControls", control_type="Group")
   |    |    |    | 
   |    |    |    | Button - '清除条目'    (L18, T321, R94, B373)
   |    |    |    | ['Button21', '清除条目', '清除条目Button']
   |    |    |    | child_window(title="清除条目", auto_id="clearEntryButton", control_type="Button")
   |    |    |    | 
   |    |    |    | Button - '清除'    (L96, T321, R172, B373)
   |    |    |    | ['Button22', '清除Button', '清除']
   |    |    |    | child_window(title="清除", auto_id="clearButton", control_type="Button")
   |    |    |    | 
   |    |    |    | Button - 'Backspace'    (L175, T321, R251, B373)
   |    |    |    | ['Button23', 'BackspaceButton', 'Backspace']
   |    |    |    | child_window(title="Backspace", auto_id="backSpaceButton", control_type="Button")
   |    |    | 
   |    |    | GroupBox - '数字键盘'    (L18, T375, R251, B589)
   |    |    | ['数字键盘GroupBox', 'GroupBox6', '数字键盘']
   |    |    | child_window(title="数字键盘", auto_id="NumberPad", control_type="Group")
   |    |    |    | 
   |    |    |    | Button - '零'    (L96, T537, R172, B589)
   |    |    |    | ['Button24', '零', '零Button']
   |    |    |    | child_window(title="零", auto_id="num0Button", control_type="Button")
   |    |    |    | 
   |    |    |    | Button - '一'    (L18, T483, R94, B535)
   |    |    |    | ['Button25', '一Button', '一']
   |    |    |    | child_window(title="一", auto_id="num1Button", control_type="Button")
   |    |    |    | 
   |    |    |    | Button - '二'    (L96, T483, R172, B535)
   |    |    |    | ['Button26', '二', '二Button']
   |    |    |    | child_window(title="二", auto_id="num2Button", control_type="Button")
   |    |    |    | 
   |    |    |    | Button - '三'    (L175, T483, R251, B535)
   |    |    |    | ['Button27', '三', '三Button']
   |    |    |    | child_window(title="三", auto_id="num3Button", control_type="Button")
   |    |    |    | 
   |    |    |    | Button - '四'    (L18, T429, R94, B481)
   |    |    |    | ['Button28', '四Button', '四']
   |    |    |    | child_window(title="四", auto_id="num4Button", control_type="Button")
   |    |    |    | 
   |    |    |    | Button - '五'    (L96, T429, R172, B481)
   |    |    |    | ['Button29', '五', '五Button']
   |    |    |    | child_window(title="五", auto_id="num5Button", control_type="Button")
   |    |    |    | 
   |    |    |    | Button - '六'    (L175, T429, R251, B481)
   |    |    |    | ['Button30', '六', '六Button']
   |    |    |    | child_window(title="六", auto_id="num6Button", control_type="Button")
   |    |    |    | 
   |    |    |    | Button - '七'    (L18, T375, R94, B427)
   |    |    |    | ['Button31', '七Button', '七']
   |    |    |    | child_window(title="七", auto_id="num7Button", control_type="Button")
   |    |    |    | 
   |    |    |    | Button - '八'    (L96, T375, R172, B427)
   |    |    |    | ['Button32', '八Button', '八']
   |    |    |    | child_window(title="八", auto_id="num8Button", control_type="Button")
   |    |    |    | 
   |    |    |    | Button - '九'    (L175, T375, R251, B427)
   |    |    |    | ['Button33', '九Button', '九']
   |    |    |    | child_window(title="九", auto_id="num9Button", control_type="Button")
   |    |    |    | 
   |    |    |    | Button - '小数分隔符'    (L175, T537, R251, B589)
   |    |    |    | ['Button34', '小数分隔符', '小数分隔符Button']
   |    |    |    | child_window(title="小数分隔符", auto_id="decimalSeparatorButton", control_type="Button")
   |    |    | 
   |    |    | Button - '正,负'    (L18, T537, R94, B589)
   |    |    | ['Button35', '正,负Button', '正,负']
   |    |    | child_window(title="正,负", auto_id="negateButton", control_type="Button")
   | 
   | Pane - ''    (L14, T94, R334, B594)
   | ['Pane', '计算器Pane']

基础线性代码

实现一个notepad(记事本)操作的内容 主要包括

  1. 打开替换窗口 关闭
  2. 编辑内容并另存为 桌面文件(修改路径)
import time
from pywinauto.application import Application


app = Application()
# 实例化一个Application()

app.start("Notepad.exe")
# main_window
main_window = app["无标题 - 记事本"]

print(main_window.get_properties())
diaologs = app.windows()
print(diaologs)


main_window.draw_outline()
# main_window.maximize()

main_window.print_control_identifiers(filename="note.ini")

main_window.menu_select("编辑(E)->替换(R)")
# print(app.top_window().get_properties())


app["替换"].print_control_identifiers(filename="replace.ini")
time.sleep(2)
app["替换"]["取消"].click()

time.sleep(2)
# app.Replace.Cancel.click()

main_window.Edit.type_keys("Hi from python interactive prompt %s " % str(dir()),with_newlines=True,with_spaces=True)
time.sleep(2)
app["记事本"].print_control_identifiers(filename="note_exit.ini")


main_window.menu_select("文件(F)->保存(S)")
time.sleep(2)

app["另存为"].print_control_identifiers(filename="note_save.ini")
diaologs = app.windows()
print(diaologs)
app["另存为"]["文件名:Edit"].type_keys(r"C:\Users\PC\Desktop\1.txt")
# 修改路径地址
time.sleep(2)

app["另存为"]["保存(S)"].click()
# app.Notepad.DontSave.click()
if app["确认另存为"]["是(Y)"]:
    app["确认另存为"]["是(Y)"].click()

注意事项

  1. 中文控件只能通过 app[control1][control2]方式访问
  2. 路径地址的变换
  3. 确认电脑有记事本软件 一般在 system32 下面的 notepad.exe ,同样通过 cmd 中 notepad 可以唤醒(路径配置在环境变量中)

结果显示

image.png