PyWinAuto入門指南
windows上支持的輔助技術列表
- Win32 API(
backend = "win32"
)(現在默認) - MFC VB6 VCL
- MS UI Automation(
backend = "uia"
) - WinForms, WPF, Store app, QT, Browsers
-
spy++
- Inspect.exe
C:Program Files (x86)Windows Kits<winver>inx64
?
如果GUI不能滿足你的要求,那使用滑鼠和鍵盤模塊也是另一種選擇,使用pyautogui吧,它可以滿足你任何要求。自動化入口
在pywinauto
中啟動程序使用一個Application
對象來調用它。
from pywinauto.application import Application# 對於Windows中自帶應用程序,直接執行,對於外部應用應輸入完整路徑app = Application(backend="uia").start(notepad.exe) #描述Notepad.exe進程中的窗口dlg_spec = app.UntitledNotepad#等待窗口真正打開actionable_dlg = dlg_spec.wait(visible)
如果你想跨進程進到另一個程序中,你可以使用Desktop
對象
from subprocess import Popenfrom pywinauto import DesktopPopen(calc.exe, shell=True)dlg = Desktop(backend="uia").Calculatordlg.wait(visible)
應用程序和桌面對象都是backend
特定的,因此無需再使用後台名稱了。
窗口規格
這高級pywinauto GUI
的核心概念,你可以使用它來模數窗口或者控制項的更多細節,無論它是否存在或者已經關閉。窗口規範還保留著有關匹配演算法、搜索演算法,這些信息將用於獲取真實的窗口或者控制項。
我們開始創建一個窗口規範:
>>> dlg_spec = app.window(title=Untitled - Notepad)# 在中文環境下# dlg_spec = app.window(title=無標題 - 記事本)>>> dlg_spec<pywinauto.application.WindowSpecification object at 0x0568B790>>>> dlg_spec.wrapper_object()<pywinauto.controls.win32_controls.DialogWrapper object at 0x05639B70># 中文 <uiawrapper.UIAWrapper - 無標題 - 記事本, Dialog, 3713039978638135481>
通過warpper_object()
方法可以執行實際窗口的查找,它返回真實的窗口或控制項的包裝器ElementNotFoundError
,這個包裝器可以通過發送動作或者檢索數據來處理窗口控制項。
但python
可以隱藏wrapper_object()
調用,簡化代碼,例如:
dlg_spec.wrapper_object().minimize() # while debuggingdlg_spec.minimize() # in production# 兩行代碼完全等價
創建窗口還有更多的標準,下面是幾個示例:
# can be multi-levelapp.window(title_re=.* - Notepad$).window(class_name=Edit)# can combine criteriadlg = Desktop(backend="uia").Calculatordlg.window(auto_id=num8Button, control_type=Button)
魔法解析屬性
Python
通過動態解析對象屬性來簡化窗口規範,但是屬性名和變數名一樣有相同規範:無空格,逗號和其他特殊符號。幸運的是,pywinauto
使用」最佳匹配「演算法來查看抵消錯別字和小的變化。
app.UntitledNotepad# is equivalent toapp.window(best_match=UntitledNotepad)
Unicode
字元和特殊符號的使用可以通過字典中的項目進行訪問(尤其對於中文來說,找不到相應的控制項就對其進行字典訪問)
app[Untitled - Notepad]# is the same asapp.window(best_match=Untitled - Notepad)
如何得到魔法屬性名稱
有幾個原則,如何將「最佳匹配「到的金光閃閃的名稱附加到控制項上。所以如果窗口規範接近於其中一個名稱,那你就能成功匹配。
- 根據標題(窗口文字,名稱):
app.Properties.OK.click()
- 按標題和控制類型:
app.Properties.OKButton.click()
- 通過控制類型和數量:
app.Properties.Button3.click()
(Button和Button1匹配相同按鈕,button2匹配下一個按鈕)
- 通過左上角的標籤和控制項類型:
app.OpenDialog.FileNameEdit.set_text("")
- 按控制項類型和項目文本:
app.Properties.TabControlSharing.select("General")
通常這些所有匹配的名稱並非都可以同時使用。要檢查指定對話框的這些名稱,可以使用print_control_identifiers()
方法。可用的最佳匹配名顯示為樹中每個控制項的Python列表。更詳細的窗口規範也可以從方法輸出中複製。
例如:
app.Properties.child_window(title="Contains:", auto_id="13087", control_type="Edit")
from pywinauto.application import Applicationapp = Application(backend="uia").start(notepad.exe)# 查到這個記事本的控制項樹dlg_spec = app[無標題 - 記事本]dlg_spec.print_control_identifiers()Dialog - 無標題 - 記事本 (L403, T241, R1203, B609)[Dialog, 無標題 - 記事本Dialog, 無標題 - 記事本]child_window(title="無標題 - 記事本", control_type="Window") | | Edit - 文本編輯器 (L411, T292, R1195, B601) | [, Edit, 0, 1] | child_window(title="文本編輯器", auto_id="15", control_type="Edit") | | | | ScrollBar - 垂直滾動條 (L1178, T292, R1195, B601) | | [垂直滾動條, 垂直滾動條ScrollBar, ScrollBar] | | child_window(title="垂直滾動條", auto_id="NonClientVerticalScrollBar", control_type="ScrollBar") | | | | | | Button - 上一行 (L1178, T292, R1195, B309) | | | [Button, 上一行, 上一行Button, Button0, Button1] | | | child_window(title="上一行", auto_id="UpButton", control_type="Button") | | | | | | Button - 下一行 (L1178, T584, R1195, B601) | | | [Button2, 下一行Button, 下一行] | | | child_window(title="下一行", auto_id="DownButton", control_type="Button") | | TitleBar - None (L427, T244, R1195, B272) | [2, TitleBar] | | | | Menu - 系統 (L411, T249, R433, B271) | | [Menu, 系統, 系統Menu, 系統0, 系統1, Menu0, Menu1] | | child_window(title="系統", auto_id="MenuBar", control_type="MenuBar") | | | | | | MenuItem - 系統 (L411, T249, R433, B271) | | | [系統2, 系統MenuItem, MenuItem, MenuItem0, MenuItem1] | | | child_window(title="系統", control_type="MenuItem") | | | | Button - 最小化 (L1056, T242, R1103, B272) | | [Button3, 最小化, 最小化Button] | | child_window(title="最小化", control_type="Button") | | | | Button - 最大化 (L1103, T242, R1149, B272) | | [Button4, 最大化Button, 最大化] | | child_window(title="最大化", control_type="Button") | | | | Button - 關閉 (L1149, T242, R1196, B272) | | [Button5, 關閉Button, 關閉] | | child_window(title="關閉", control_type="Button") | | Menu - 應用程序 (L411, T272, R1195, B291) | [應用程序, Menu2, 應用程序Menu] | child_window(title="應用程序", auto_id="MenuBar", control_type="MenuBar") | | | | MenuItem - 文件(F) (L411, T272, R463, B291) | | [文件(F)MenuItem, 文件(F), MenuItem2] | | child_window(title="文件(F)", control_type="MenuItem") | | | | MenuItem - 編輯(E) (L463, T272, R516, B291) | | [編輯(E)MenuItem, 編輯(E), MenuItem3] | | child_window(title="編輯(E)", control_type="MenuItem") | | | | MenuItem - 格式(O) (L516, T272, R572, B291) | | [格式(O)MenuItem, 格式(O), MenuItem4] | | child_window(title="格式(O)", control_type="MenuItem") | | | | MenuItem - 查看(V) (L572, T272, R626, B291) | | [查看(V), 查看(V)MenuItem, MenuItem5] | | child_window(title="查看(V)", control_type="MenuItem") | | | | MenuItem - 幫助(H) (L626, T272, R681, B291) | | [幫助(H), 幫助(H)MenuItem, MenuItem6] | | child_window(title="幫助(H)", control_type="MenuItem")Process finished with exit code 0
一些例子
下面的這些例子所包括:注意:示例是依賴於語言的,他們僅適用於所coding的產品語言,如下所示例的均為英文環境。
mspaint.py
控制MSPaint
notepad_fast.py
使用快速時間設置來控制筆記本
notepad_slow.py
使用慢時間設置來控制筆記本
notepad_item.py
使用項目,然後屬性訪問控制項記事本。
misc_examples.py
顯示一些異常以及如何獲取控制標識符。
save_from_internet_explorer.py
從Internet Explorer保存網頁。
save_from_firefox.py
從Firefox保存網頁。
get_winrar_info.py
如何做多語言自動化的例子。這不是一個理想的例子(適用於法語,捷克語和德語WinRar)
forte_agent_sample.py
處理複雜的應用程序的例子是非常動態的,並且在啟動時經常給出不同的對話框。
windowmediaplayer.py
另一個例子 - 處理ListView中的複選框。
test_sakura.py
,test_sakura2.py
自動化一個Japanase產品的兩個例子。
在命令行自動化記事本
請按照如下示例運行
from pywinauto.application import Applicationimport timeapp = Application().start(notepad.exe)time.sleep(1)app[ 無標題 - 記事本 ].menu_select("編輯(&E) -> 替換(&R)..")time.sleep(1)app[替換].取消.click()# 沒有with_spaces 參數空格將不會被鍵入。請參閱SendKeys的這個方法的文檔,因為它是SendKeys周圍的薄包裝。app[ 無標題 - 記事本 ].Edit.type_keys("Hi from Python interactive prompt %s" % str(dir()), with_spaces = True)app[ 無標題 - 記事本 ].menu_select(文件(&F) -> 退出(&X))# 在這時候不清楚「不保存」的按鈕名就對app[記事本] 使用print_control_identifiers()app[記事本].Button2.click()
推薦閱讀:
※迷宮 待添加
※為什麼有有很多人轉去學習CS ?
※1-13 改行CS的常見問題討論
※工作效率太低怎麼辦?不如試試雙顯示屏或多顯示屏!
※愚人節,說說假新聞和謠言,它們傳播得比真相更快