Windows 上的桌面程序不像网页那样有一套统一的 DOM 可以查。传统的 Win32 程序把按钮、输入框、列表框画在窗口里,较新的程序用 WPF、WinForms 或 Qt 重新搭一遍界面,走的又是另一套控件体系;同一段「点开菜单、填两个框、点确定」的操作,在不同框架下要调用的接口完全不同。结果是桌面端的重复劳动大多只能靠人手:回归测试一遍遍点,批量填单一条条抄,线上出问题按记忆复现。pywinauto 想解决的就是这一层——它是一套 Python 模块,把窗口里的控件按名字暴露成对象,让你写 `app.窗口名.控件名.click()` 这样的脚本去驱动它们,底层可以走 Win32 API,也可以走微软的 UI Automation。脚本能读、能存档、能塞进持续集成,比录制回放稳得多。下面讲清它的能力边界、两种后端怎么选、安装与上手的具体步骤,以及它在 Linux 与 macOS 上目前处于什么阶段。
pywinauto 是什么?
pywinauto 是一套用来自动化 Microsoft Windows 图形界面的 Python 模块,仓库建在 GitHub 的 pywinauto 组织下,2015 年 5 月创建,采用 BSD 3-clause 授权,目前有 6,300 余 star、790 个 fork、3,248 次提交。它的能力可以分两层看:最基础的一层是把鼠标与键盘动作送到指定的窗口对话与控件上;再往上一层是从控件里读文本、读状态、读层级,让脚本能判断界面此刻是什么样子,而不是盲目点击固定坐标。代码历史比仓库更早,初版由 Mark Mc Mahon 在 2006 年前后写成,此后 Intel 参与过 0.5.x 维护,现在由开源社区在业余时间推进。技术路线上它同时支持 Win32 API 与微软 UI Automation 两套接口,2026 年 10 月 15 日发布的 1.0.0b1 又把后端扩展到 Linux 的 atspi、macOS 的 ax、Windows 的 WPF 与 Qt5/Qt6,属于一次跨度很大的重构。

核心功能
pywinauto 的功能围绕”找到控件—操作控件—等它变状态—把结果留证”这条链展开,重点解决两件事:让脚本能稳定定位到界面元素,让等待与断言不必靠自己写 sleep。它不提供录制回放的图形工具,所有能力都以 Python 接口暴露,所以写得出来什么取决于你对控件树的理解程度。下面几条是日常用得最多的。
- 双后端定位控件——按程序的技术栈换视角:`backend=”win32″` 走传统 Win32 API,适合老式 MFC、VB6、Delphi 程序;`backend=”uia”` 走微软 UI Automation,能读 WPF、WinForms 与部分 Qt 程序暴露的自动化树。同一个应用用两种后端看到的控件层级不同,选错后端会「什么都找不到」。
- 窗口与控件当对象——脚本接近自然语言:`Application().start()` 之后,用 `app.UntitledNotepad.Edit.type_keys()`、`app.AboutNotepad.OK.click()` 这样的写法逐级调下去,名字来自控件标题或自动化 ID,读起来就是操作步骤本身。
- 控件树可打印——写选择器不用猜:`print_control_identifiers()` 会把整个窗口的控件层级、类名、标题、自动化 ID、当前状态整棵树打出来,照着它挑路径;配合 Spy++ 或 Inspect 这类系统工具看界面结构,定位一次就能固定下来。
- 真实输入与消息两种操作方式——按程序是否拦截消息切换:`click()` 直接发窗口消息,`click_input()` 移动真实光标再点,`type_keys()` 键盘输入并可指定是否插入空格,`menu_select(“Help->About Notepad”)` 用路径点菜单。前者不抢焦点,后者更接近人工操作,遇到拦截消息的程序就换一种。
- 等待与状态断言——替代写死的 sleep:`wait()` 等控件出现,`wait_not(‘visible’)` 等对话框关掉再往下走,能避开「点了按钮弹窗还没出来」这类竞态,也就把脚本从「睡三秒再说」里救出来。
- 截图与控件快照——给失败留证:调用 `capture_as_image()` 可以把单个控件存成图片,需要额外装 Pillow;配合用例失败时自动截图,排查比对着日志猜快得多。
- 跨平台后端——Linux 与 macOS 进入测试阶段:1.0.0b1 新增 Linux atspi 与 macOS ax 后端,`mouse`、`keyboard` 两个输入模块本来就同时支持 Windows 与 Linux;这些后端标注为 beta 质量,接口会变。
- 可进持续集成——仓库自带流水线配置:项目同时配了 AppVeyor 与 Travis 两套构建,单元测试集中在 `pywinauto/unittests/testall.py`,脚本能在构建机上跑,适合把桌面回归挂到提交流程里。
使用场景
pywinauto 的适用面集中在「必须通过界面操作、又拿不到程序内部接口」的场合:桌面客户端没有 API 可调,第三方软件不能改源码,老系统只剩界面一层。它不负责生成稳定的测试数据,也不做图像识别,遇到纯自绘界面(整块画布自己绘制的程序)仍然读不到控件,只能退回坐标点击。下面按人群列几个典型用法。
| 人群/角色 | 场景描述 | 推荐指数 |
|---|---|---|
| 桌面应用测试工程师 | 把「打开→登录→新建→保存」这条主流程写成脚本,每次发版前跑一遍,替代手工回归 | ★★★★★ |
| 办公与 RPA 自动化 | 批量往 Excel、ERP 客户端、行业软件里灌数据,一次写脚本长期复用 | ★★★★☆ |
| 维护老系统的运维 | 只拿到 exe、没有源码也没有接口,只能靠界面完成操作 | ★★★★☆ |
| 应用开发者 | 复现用户报的界面 bug 时,用脚本稳定重现那串点击,比手点十遍可靠 | ★★★★☆ |
| 做桌面数据采集的人 | 从客户端列表里逐条读取文本并导出,前提是控件走标准接口 | ★★★☆☆ |
| 跨平台团队 | 希望在 Linux 或 macOS 上跑同一套 UI 自动化,目前后端仍是 beta | ★★☆☆☆ |
操作指南
从零到跑通第一个脚本大约十分钟,卡住的地方通常不是 Python 语法,而是后端选错或控件路径写不准。建议先拿记事本这类所有人都有、控件结构又简单的程序练手。
- 确认 Python 环境,用 `pip install -U pywinauto` 安装;用 conda 的话执行 `conda install -c conda-forge pywinauto`。Windows 下会自动带上 pywin32 与 comtypes 两个依赖,Linux 需要额外的 python-xlib。
- 想给控件截图留证,再装一个 Pillow,`capture_as_image()` 才会生效。
- 打开 pywinauto 的入门文档,先读「核心概念」那一节,重点看 `Application`、窗口规格与后端三者的关系,这决定了后面怎么选控件。
- 用 Spy++(Visual Studio 自带)或 Inspect 打开目标程序,确认它属于 Win32 还是 UIA 体系——老式程序看得到窗口类名就用「win32」,WPF、WinForms 这类用「uia」。
- 写第一段脚本:`Application().start()` 启动程序,再用 `print_control_identifiers()` 把控件树打出来,照着树里的名字决定路径。
- 把动作接上去:`menu_select()` 点菜单、`type_keys()` 填内容、`click()` 或 `click_input()` 点按钮,中间用 `wait()` / `wait_not()` 卡住状态变化。
- 跑通后把它整理成用例:断言读到的文本或控件状态,失败时截图,再挂到构建流程里定时执行。
两点提醒:以管理员身份运行的程序,脚本也必须以管理员身份启动,否则操作系统会直接挡住输入与读取;同一个应用切后端时不要混用两套路径,`win32` 下认的标题在 `uia` 下未必存在。
支持平台
pywinauto 的主战场是 Windows:PyPI 上的元数据只声明支持 Microsoft Windows,0.6.x 系列一直如此,WPF、WinForms、MFC 与部分 Qt 程序都在覆盖范围内。2026 年 10 月的 1.0.0b1 把边界往外推了一步,Linux 的 atspi 后端与 macOS 的 ax 后端都以 beta 质量发布,Windows 的 WPF 后端与 Qt5/Qt6 后端同样是 beta;这些新后端接口还在调整,官方明确标注了质量等级,生产环境接入前建议先在小范围验证。输入模拟模块 `mouse` 与 `keyboard` 本身同时支持 Windows 与 Linux。
产品定价
pywinauto 免费,开源协议是 BSD 3-clause,从 0.6.0 起一直沿用;更早的 0.5.4 及之前版本按 LGPL v2.1 或更新版本发布。没有商业版、没有订阅层级,也没有按席位或调用次数计费的设计,全部能力都在同一个包里。项目靠 PayPal 捐赠与社区贡献维持,维护者说明新功能是在业余时间开发的,所以问题响应速度取决于有没有人接手。需要留意版本节奏:PyPI 上的稳定版是 0.6.9(2025 年 1 月发布,也是最后一个兼容 Python 2.7 的版本),1.0.0b1 是预发布版本,要装它得显式加预发布参数。
常见问题
Q:需要装什么?对 Python 版本有什么要求?
`pip install -U pywinauto` 一条命令即可,Windows 上会自动带上 pywin32 与 comtypes。Python 2.7 的支持在 1.0.0b1 里已经被移除,现在按 Python 3 使用;如果项目还在 Python 2.7 上,只能停在 0.6.9。
Q:win32 和 uia 两种后端该怎么选?
看目标程序用什么技术写的。老式 Win32 程序(MFC、VB6、Delphi 等)用 `backend=”win32″`,能看到窗口类名和控件句柄;WPF、WinForms 以及走 UI Automation 的程序用 `backend=”uia”`。判断方法是先用 `print_control_identifiers()` 各打一次,哪边能看到你需要的控件就用哪边。注意 1.0.0b1 起 Windows 的默认后端已经从 win32 改成 uia,升级时旧脚本可能要显式指定后端。
Q:能不能在 Linux 或 macOS 上跑?
部分能。1.0.0b1 提供了 Linux 的 atspi 与 macOS 的 ax 后端,都是 beta 质量,覆盖面和稳定性都不如 Windows;`mouse`、`keyboard` 这类输入模拟模块在 Windows 与 Linux 上都能用。跨平台做 UI 自动化的项目,建议把 Linux、macOS 部分当成探索性能力,别直接替代现有方案。
开发者小结
pywinauto 的价值在于把「按控件属性写脚本」这条路走通了:不依赖固定坐标,不做容易碎的图像匹配,控件有名字就按名字调,脚本读起来就是操作步骤,能进版本控制也能进持续集成,这是它二十年还在被使用的原因。它适合必须通过界面操作、又拿不到程序内部接口的场景——桌面客户端回归测试、行业软件批量灌数据、老系统维护、UI bug 稳定复现;配合 Spy++ 或 Inspect 先摸清控件树,上手成本并不高。边界也要清楚:纯自绘界面读不到控件;以管理员权限运行的程序要求脚本同样提权;1.0.0b1 的 Linux、macOS、WPF、Qt 后端都是 beta,接口会变;项目维护靠业余时间,522 个未关闭的 issue 与 PR 说明排队是常态,遇到冷门框架的问题不保证有人及时接手。把它当成 Windows 桌面自动化的一层稳定底座,而不是跨平台 UI 测试的万用方案,预期就摆对了。
