PyWinAuto入門指南

PyWinAuto入門指南

windows上支持的輔助技術列表

  • Win32 API(backend = "win32")(現在默認)
  • MFC VB6 VCL
  • MS UI Automation(backend = "uia")
  • WinForms, WPF, Store app, QT, Browsers

GUI觀察

  • 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)

如何得到魔法屬性名稱

有幾個原則,如何將「最佳匹配「到的金光閃閃的名稱附加到控制項上。所以如果窗口規範接近於其中一個名稱,那你就能成功匹配。

  1. 根據標題(窗口文字,名稱):app.Properties.OK.click()
  1. 按標題和控制類型:app.Properties.OKButton.click()
  1. 通過控制類型和數量:app.Properties.Button3.click()(Button和Button1匹配相同按鈕,button2匹配下一個按鈕)
  1. 通過左上角的標籤和控制項類型:app.OpenDialog.FileNameEdit.set_text("")
  1. 按控制項類型和項目文本: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.pytest_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的常見問題討論
工作效率太低怎麼辦?不如試試雙顯示屏或多顯示屏!
愚人節,說說假新聞和謠言,它們傳播得比真相更快

TAG:入門指南 | 計算機科學 | Python |