一、安装与工具
安装
pip install pywinauto==0.6.9
UI 对象检查工具(定位元素用)
| 工具 |
说明 |
| UISpy |
微软官方工具,推荐使用 |
| Inspect.exe |
Windows SDK 自带 |
| Spy++ |
Visual Studio 自带 |
判断能否用 pywinauto 自动化:用 UISpy 能定位到元素 → 可以;不能定位 → 不能用(如企业微信、Flutter应用)。
二、两种后端模式(backend)
| 模式 |
适用场景 |
win32 |
传统 MFC、VB6 等旧架构应用 |
uia |
现代 WinForms、WPF、Qt5 应用(推荐) |
from pywinauto.application import Application
# 启动应用
app = Application(backend="uia").start("notepad.exe")
# 连接已运行的应用
app = Application(backend="uia").connect(process=12345)
app = Application(backend="uia").connect(title="QQMusic")
三、定位窗口
window() 方法参数
| 参数 |
说明 |
示例 |
title |
精确匹配标题 |
title="计算器" |
title_re |
正则匹配 |
title_re=".*Sublime.*" |
class_name |
窗口类名 |
class_name="Notepad" |
best_match |
模糊匹配 |
best_match="untitled" |
win = app.window(title_re=".*Sublime Text.*")
win.wait("visible") # 等待窗口可见
快速获取顶级窗口
win = app.top_window() # 不一定准确,谨慎使用
四、等待机制(重要!)
GUI 行为不稳定,必须加等待。
wait() / wait_not()
win.wait("exists") # 窗口句柄有效
win.wait("visible") # 窗口可见
win.wait("enabled") # 控件未禁用
win.wait("ready") # 可见且启用
win.wait("active") # 窗口处于活动状态
win.wait_not("visible") # 等待窗口消失
wait_until()
from pywinauto.timings import wait_until
wait_until(10, 2, lambda: win.is_visible(), True) # 10秒超时,每2秒检查一次
五、定位控件
child_window() 方法
| 参数 |
说明 |
title / title_re |
标题/正则匹配 |
auto_id |
自动化 ID(最稳定) |
control_type |
控件类型(Button、Edit、List等) |
found_index |
同属性多个控件时指定索引 |
# 基本定位
edit = win.child_window(auto_id="searchBox", control_type="Edit")
# 多个相同控件时用索引
btn = win.child_window(auto_id="MenuBar", control_type="MenuBar", found_index=1)
打印控件树(调试利器)
win.print_control_identifiers() # 打印所有子控件信息
动态解析(不推荐,有空格时用)
win['应用程序'] # 等价于 win.child_window(best_match='应用程序')
六、控件操作
点击操作
| 方法 |
说明 |
click_input() |
鼠标左键单击 |
right_click_input() |
右键单击 |
double_click_input() |
双击 |
btn.click_input()
文本操作
| 方法 |
说明 |
texts() |
返回所有文本(列表) |
window_text() |
返回主文本(字符串) |
print(win.window_text()) # 窗口标题
print(btn.window_text()) # 按钮文字
键盘输入
# 方式1:type_keys(推荐,直接作用于控件)
edit.type_keys("Hello World")
edit.type_keys("换行{ENTER}", with_newlines=True)
edit.type_keys("带空格", with_spaces=True)
# 特殊按键
edit.type_keys("{ENTER}") # 回车
edit.type_keys("{TAB}") # Tab
edit.type_keys("{BACKSPACE}") # 退格
edit.type_keys("{ENTER 2}") # 按两次回车
# 转义特殊字符
edit.type_keys("1{+}2=3") # 正确显示 "1+2=3"
# 方式2:全局键盘(不推荐,依赖焦点)
from pywinauto.keyboard import send_keys
send_keys("123")
七、鼠标操作(mouse 模块)
from pywinauto import mouse
# 获取控件位置
rect = btn.rectangle() # 返回矩形 (top,left,right,bottom)
mid_point = btn.rectangle().mid_point() # 返回中心坐标 (x, y)
# 鼠标操作
mouse.click(coord=(x, y)) # 左键单击
mouse.double_click(coord=(x, y)) # 双击
mouse.right_click(coord=(x, y)) # 右键单击
mouse.scroll(coord=(x, y), wheel_dist=-500) # 滚动(负=向下,正=向上)
mouse.move(coord=(x, y)) # 移动鼠标
八、窗口操作
| 方法 |
说明 |
close() |
关闭窗口 |
maximize() / minimize() |
最大化/最小化 |
restore() |
恢复正常大小 |
set_focus() |
设置焦点到窗口 |
is_maximized() / is_minimized() |
检查状态 |
win.minimize()
win.restore()
win.set_focus()
九、菜单操作
获取菜单项
menu = win['应用程序'] # 或 win.child_window(title="应用程序")
items = menu.items() # 获取所有菜单项
item = menu.item_by_index(0) # 按索引获取
点击菜单路径
# 方法1:item_by_path
menu.item_by_path("File -> Save").click_input()
# 方法2:menu_select(更简洁)
win.menu_select("File -> Save")
多层菜单(需要定位子窗口)
# 点击 File -> Open Recent
menu.item_by_path("File -> Open Recent").click_input()
# 定位到 Open Recent 子窗口
openRecent_win = win.child_window(title="Open Recent", control_type="Window")
clear_item = openRecent_win.child_window(title="Clear Items", control_type="MenuItem")
clear_item.click_input()
十、列表控件操作
| 方法 |
说明 |
get_items() |
获取所有列表项 |
item_count() |
获取列表项数量 |
get_item(row=0) |
获取指定行项目 |
list_ctrl = win.child_window(auto_id="HomeListView", control_type="List")
# 获取数量
count = list_ctrl.item_count()
# 获取第一项
first_item = list_ctrl.get_item(row=0)
# 获取所有项
all_items = list_ctrl.get_items()
十一、常见自动化场景模板
1. 启动/连接应用 + 完整流程
from pywinauto import Application
from pywinauto import mouse
import time
# 启动应用
app = Application(backend="uia").start("D:\\app\\QQMusic.exe")
# 或连接已运行的应用
app = Application(backend="uia").connect(process=12345)
# 定位主窗口
win = app.window(title="QQMusic")
win.wait("visible")
# 定位控件并操作
search_box = win.child_window(auto_id="searchBox", control_type="Edit")
search_box.click_input()
search_box.type_keys("周杰伦")
# 点击搜索按钮
search_btn = win.child_window(title="搜索", control_type="Button")
search_btn.click_input()
# 验证结果
result_list = win.child_window(control_type="List")
assert result_list.item_count() > 0
# 关闭应用
win.close()
2. 带夹具(fixture)的测试类
import pytest
from pywinauto import Application
@pytest.fixture(scope="session")
def app():
app = Application(backend="uia").start("notepad.exe")
win = app.window(title_re=".*Notepad")
win.wait("visible")
yield app
win.close()
def test_notepad_input(app):
win = app.window(title_re=".*Notepad")
edit = win.child_window(control_type="Document")
edit.type_keys("Hello Pywinauto!")
assert "Hello" in edit.window_text()
十二、注意事项与最佳实践
| 要点 |
说明 |
| 优先用 auto_id |
最稳定,不受界面文字变化影响 |
| 必须加等待 |
GUI 行为不稳定,wait() 是必须的 |
不要用 __init__ |
pytest 测试类中不能用 __init__,用 fixture |
| 鼠标操作优先用控件方法 |
能用 click_input() 就不用 mouse.click() |
| 多层菜单需逐层定位 |
子菜单可能在新窗口中 |
| 列表验证用数量变化 |
验证新增/删除操作时,检查 item_count 变化 |
所有评论(0)