pywinauto使用和学习笔记
安装
pip install pywinauto
在线文档:
https://www.kancloud.cn/gnefnuy/pywinauto_doc/1193035
以下是pywinauto常用方法的完整汇总,涵盖从程序连接、窗口操作、控件定位到键鼠模拟的全流程,并附带实战案例。
一、安装与导入
pip install pywinauto1from pywinauto.application import Application 2from pywinauto import mouse, keyboard 3from pywinauto.keyboard import send_keys二、启动与连接应用程序
pywinauto支持两种后端:uia(适用于现代 WPF/WinForms/UWP 应用)和win32(适用于传统 Win32 应用)。推荐优先使用uia,遇到报错时切换win32。
1# 启动新程序 2 app = Application(backend="uia").start("notepad.exe") 3 4# 连接已运行的程序(支持多种定位方式) 5 app = Application(backend="uia").connect(title="微信") # 按标题 6 app = Application(backend="uia").connect(title_re=".*微信.*") # 按正则标题 7 app = Application(backend="uia").connect(path=r"D:\WeChat\WeChat.exe") # 按路径 8 app = Application(backend="uia").connect(process=12345) # 按进程ID 9 app = Application(backend="uia").connect(handle=65552) # 按窗口句柄 10 app = Application(backend="uia").connect(class_name="Notepad") # 按类名三、窗口定位与查找
1# 精确匹配标题 2 win = app.window(title="无标题 - 记事本") 3 4# 正则匹配标题(推荐,兼容动态标题) 5 win = app.window(title_re=".*无标题.*") 6 7# 通过类名定位 8 win = app.window(class_name="WeChatMainWndForPC") 9 10# 字典访问方式(支持中文,推荐) 11 win = app["无标题 - 记事本"] 12 13# 获取最顶层窗口 14 win = app.top_window() 15 16# 获取所有窗口列表 17 dialogs = app.windows() 18 19# 通过子控件定位(支持多级链式调用) 20 child = win.child_window(title="确定", control_type="Button") 21 child = win.child_window(title="确认").child_window(auto_id="btnOK")子控件定位常用参数
| 参数 | 说明 |
|---|---|
title | 控件标题,对应 Inspect 中 Name 字段 |
title_re | 正则匹配标题 |
class_name | 类名 |
control_type | 控件类型(Button、Edit、Text 等) |
auto_id | AutomationId |
found_index | 多个匹配时指定索引 |
handle | 窗口句柄 |
四、控件遍历与调试
1# 打印控件层级树(调试神器,排查定位问题的第一步) 2 win.print_control_identifiers() 3 4# 保存到文件 5 win.print_control_identifiers(depth=None, filename="controls.txt") 6 7# 遍历所有按钮 8 all_buttons = win.descendants(control_type="Button") 9 10# 获取子元素列表 11 children = win.children() 12 13# 获取父元素 14 parent = child.parent()五、窗口状态操作
1 win.maximize() # 最大化 2 win.minimize() # 最小化 3 win.restore() # 恢复正常大小 4 win.close() # 关闭窗口 5 win.set_focus() # 设置焦点到前台 6 7# 获取窗口状态(0:正常, 1:最大化, 2:最小化) 8 state = win.get_show_state() 9 10# 判断窗口状态 11 win.is_minimized() # 是否最小化 12 win.is_normal() # 是否正常 13 win.is_visible() # 是否可见 14 15# 获取窗口标题 16 title = win.window_text() 17 18# 获取窗口坐标与尺寸 19 rect = win.rectangle() 20 print(f"Left={rect.left}, Top={rect.top}, Width={rect.width()}, Height={rect.height()}") 21 22# 获取窗口中心点 23 center = rect.mid_point() 24 print(f"中心点: X={center.x}, Y={center.y}") 25 26# 获取进程ID 27 pid = win.process_id()六、控件交互操作
1# 输入文本(两种方法) 2 edit.set_text("你好世界") # 直接设置文本值,光标在开头,不支持快捷键 3 edit.type_keys("你好世界") # 模拟键盘输入,光标在末尾,支持快捷键(推荐) 4 5# 鼠标点击 6 button.click_input() # 模拟真实鼠标点击(推荐) 7 button.click() # 发送消息点击(部分控件不生效) 8 9# 复选框 10 checkbox.check() # 勾选 11 checkbox.uncheck() # 取消勾选 12 13# 下拉框选择 14 combo.select("选项名") 15 16# 菜单操作 17 win.menu_select("文件->保存") 18 19# 获取控件文本 20 text = edit.window_text() 21 22# 判断控件是否可用 23 is_enabled = button.is_enabled() 24 25# 获取元素坐标 26 rect = button.rectangle() print(rect.left,rect.top,rect.right,rect.bottom) print(f"控件位置: {rect.left}, {rect.top}") print(f"控件大小: {rect.width()} x {rect.height()}") #获取中心坐标 27 center = rect.mid_point() x=center.x y=center.y七、等待与稳定性机制
1# 等待窗口就绪(可见且可用) 2 win.wait('ready', timeout=10) 3 4# 等待窗口可见 5 win.wait('visible') 6 7# 等待窗口存在(最小化状态下安全) 8 win.wait('exists') 9 10# 等待窗口消失 11 win.wait_not('visible') 12 13# 判断窗口是否存在 14 if app.window(title='确认').exists(): 15 app.window(title='确认').child_window(title='确定').click()八、键盘操作
键盘操作的核心是send_keys()和type_keys(),支持特殊按键和组合键。
修饰符符号
| 符号 | 含义 |
|---|---|
^ | Ctrl |
% | Alt |
+ | Shift |
常用快捷键示例
1from pywinauto.keyboard import send_keys 2 3 send_keys("^s") # Ctrl+S(保存) 4 send_keys("^a") # Ctrl+A(全选) 5 send_keys("^c") # Ctrl+C(复制) 6 send_keys("^v") # Ctrl+V(粘贴) 7 send_keys("%{F4}") # Alt+F4(关闭窗口) 8 send_keys("^+s") # Ctrl+Shift+S 9 send_keys("{ENTER}") # 回车 10 send_keys("{TAB}") # Tab键 11 send_keys("{ESC}") # Esc键 12 send_keys("{BACKSPACE}") # 退格 13 send_keys("{DELETE}") # Delete键 14 send_keys("{UP}") # 上方向键 15 send_keys("{DOWN}") # 下方向键在控件中输入
1# 在编辑框中输入文字并回车 2 edit.type_keys("Hello World!{ENTER}第二行内容") 3 4# 通过菜单快捷键操作 5 send_keys("%F") # Alt+F(打开文件菜单)九、鼠标操作
1 from pywinauto import mouse 2 3# 左键单击(绝对屏幕坐标) 4 mouse.click(button='left', coords=(500, 300)) 5 6# 双击 7 mouse.double_click(button='left', coords=(500, 300)) 8 9# 右键点击 10 mouse.click(button='right', coords=(500, 300)) 11 12# 鼠标移动 13 mouse.move(coords=(500, 300)) 14 15# 滚轮滚动(正数向上,负数向下) 16 mouse.scroll(coords=(500, 300), wheel_dist=3) 17 18# 按下和释放(拖拽操作) 19 mouse.press(button='left', coords=(100, 100)) 20 mouse.release(button='left', coords=(500, 500)) 21 22# 相对窗口点击 23 win.click_input(button='left', coords=(100, 50))十、常用方法
1:pywinauto 截图
在 pywinauto 中,对窗口或控件进行截图非常简单,核心方法是capture_as_image()。该方法会返回一个Pillow库的Image对象,你可以直接对其进行处理或保存。
1. 前置准备
在使用截图功能前,请确保你已经安装了pywinauto和Pillow库。如果没有安装Pillow,调用截图方法时会报错:
1pip install pywinauto Pillow2. 基础截图示例
你可以对整个窗口或窗口内的特定控件进行截图。以下是基于记事本应用的完整示例:
1import time 2from pywinauto.application import Application 3 4# 启动记事本应用 5app = Application(backend="uia").start('notepad.exe') 6time.sleep(1) # 等待窗口加载 7 8# 获取记事本主窗口和编辑控件 9notepad = app['无标题 - 记事本'] 10edit = notepad['Edit'] 11 12# 1. 对整个窗口进行截图 13window_image = notepad.capture_as_image() 14window_image.save('notepad_window.png') # 保存截图 15window_image.show() # 显示截图 16 17# 2. 对特定控件(编辑框)进行截图 18control_image = edit.capture_as_image() 19control_image.save('notepad_edit.png') # 保存截图3. 进阶用法:结合坐标进行局部截图
结合你之前了解的控件坐标信息,如果你需要截取控件周围的特定区域,或者capture_as_image()遇到被遮挡等失效情况,可以配合Pillow的ImageGrab和控件的rectangle()坐标来实现精准截图:
python
编辑
1from PIL import ImageGrab 2 3# 获取控件的矩形边界坐标 4rect = edit.rectangle() 5 6# 使用 ImageGrab 根据坐标进行截图 (left, top, right, bottom) 7screenshot = ImageGrab.grab(bbox=(rect.left, rect.top, rect.right, rect.bottom)) 8screenshot.save('custom_area.png')💡 常见问题排查
- 报错
AttributeError: 'NoneType' object has no attribute 'save':这通常是因为没有安装Pillow库,或者目标窗口/控件未正确获取到。请先运行pip install Pillow并检查窗口定位是否正确。 - 截图包含其他窗口背景:如果目标窗口被其他窗口遮挡,
capture_as_image()可能会截取到叠加的背景。建议在截图前使用dlg.restore()或dlg.set_focus()将目标窗口置于前台。 - 找不到控件:可以使用
notepad.print_control_identifiers()方法来打印窗口控件树,帮助调试并确认控件的标题或属性是否正确。
十一、实战案例
案例一:自动操作记事本
1 from pywinauto.application import Application 2 import time 3 4# 启动记事本 5 app = Application(backend="uia").start("notepad.exe") 6 win = app.window(title_re=".*无标题.*") 7 win.wait('ready') 8 9# 输入内容 10 edit = win.child_window(control_type="Edit") 11 edit.type_keys("Hello, pywinauto!{ENTER}这是自动化测试内容。") 12 13# 保存文件(Ctrl+S) 14 win.type_keys("^s") 15 time.sleep(1) 16 17# 处理保存对话框 18 save_dlg = app.window(title="另存为") 19 save_dlg.child_window(title="文件名:", control_type="Edit").set_text("test.txt") 20 save_dlg.child_window(title="保存(&S)", control_type="Button").click_input() 21 22# 关闭记事本 23 win.close()案例二:自动操作微信发送消息
1 import time 2 from pywinauto.application import Application 3 from pywinauto import mouse 4 from pywinauto.keyboard import send_keys 5 6# 连接已运行的微信 7 app = Application(backend="uia").connect(path=r"D:\software\WeChat\WeChat.exe") 8 win = app.window(title="微信", class_name="WeChatMainWndForPC") 9 10# 获取元素中心点坐标的辅助函数 11 def get_center(ele): 12 rect = ele.rectangle() 13 return (int((rect.left + rect.right) / 2), int((rect.top + rect.bottom) / 2)) 14 15# 点击"文件传输助手" 16 file_helper = win.child_window(title="文件传输助手", control_type="ListItem") 17 mouse.click(button='left', coords=get_center(file_helper)) 18 time.sleep(1) 19 20# 定位输入框并输入内容 21 edit = win.child_window(title="输入", control_type="Edit") 22 edit.type_keys("这是pywinauto自动发送的消息") 23 time.sleep(0.5) 24 25# 按回车发送 26 send_keys("{ENTER}")案例三:自动登录程序
1 from pywinauto.application import Application 2 import time 3 4 app = Application(backend="uia").start("login.exe") 5 main_win = app.window(title="登录") 6 main_win.wait('ready') 7 8# 输入账号密码 9 main_win.child_window(title="用户名", control_type="Edit").type_keys("test_user") 10 main_win.child_window(title="密码", control_type="Edit").type_keys("123456") 11 12# 点击登录按钮 13 main_win.child_window(title="登录", control_type="Button").click_input() 14 time.sleep(2) 15 16# 检查是否登录成功 17 if app.window(title="主界面").exists(): 18 print("登录成功!")💡 核心避坑指南
- Backend 切换:
uia报错时切换win32,尤其是最小化窗口操作时win32更稳定。 - 最小化窗口:使用
wait('exists')而非wait('visible'),否则超时报错。 - DPI 缩放:Windows 缩放比例非 100% 时,坐标可能偏移,需做缩放换算。
- 调试第一步:遇到找不到控件,先调用
print_control_identifiers()打印控件树确认属性。 - 开启日志:
from pywinauto import actionlogger; actionlogger.enable()可输出详细操作日志,方便排查问题。
