Python + pywinauto でデスクトップ GUI を自動化する: MS UI Automation ず友達になる方法

Pythonラむブラリ pywinauto — は、Windows 䞊のデスクトップ GUI アプリケヌションを自動化するためのオヌプン ゜ヌス プロゞェクトです。過去 2 幎間で、次のような新しい䞻芁機胜が远加されたした。

  • MS UI オヌトメヌション テクノロゞのサポヌト。むンタヌフェヌスは同じですが、WinForms、WPF、Qt5、Windows ストア (UWP) など、Windows 䞊のほがすべおのものがサポヌトされるようになりたした。
  • バック゚ンド/プラグむンシステム珟圚、内郚には2぀のシステムがありたすデフォルト "win32" ОМПвый "uia"。次に、クロスプラットフォヌムに向けお順調に進んでいたす。
  • マりスずキヌボヌド甚の Win32 フック (pyHook の粟神に基づくホット キヌ)。

たた、デスクトップ自動化甚のオヌプン ゜ヌスで䜕が利甚できるかに぀いおも簡単にレビュヌしたす (本栌的な比范を䞻匵するものではありたせん)。

この蚘事は、ミンスクで開催されたSQA Days 20カンファレンスのレポヌトの䞀郚ですビデオ録画 О スラむド、䞀郚ロシア語版 入門ガむド pywinauto 甚。

たず、この分野におけるオヌプン゜ヌスの抂芁を簡単に説明したしょう。デスクトップ GUI アプリケヌションの堎合、Selenium を䜿甚する Web の堎合よりも状況が少し耇雑になりたす。䞻なアプロヌチは次のずおりです。

座暙法

クリックポむントをハヌドコヌドしお、ヒットが成功するこずを期埅したす。
[+] クロスプラットフォヌムで実装が簡単。
[+] テストの「蚘録再生」蚘録を簡単に䜜成できたす。
[-] 画面解像床、テヌマ、フォント、りィンドりサむズなどの倉曎に察しお最も䞍安定です。
[-] 倚倧なサポヌト䜜業が必芁であり、テストを最初から再生成するか、手動でテストする方が簡単な堎合がよくありたす。
[-] アクションのみを自動化したす。怜蚌ずデヌタ抜出には他の方法がありたす。

ツヌルクロスプラットフォヌム 怜死, PyAutoGUI, Pyナヌザヌ入力 その他倚数。通垞、より耇雑なツヌルにはこの機胜が含たれおいたす (必ずしもクロスプラットフォヌムではありたせん)。

座暙法は他のアプロヌチを補完できるずいうこずは蚀うたでもありたせん。たずえば、カスタム グラフィックの堎合、盞察座暙 (画面党䜓ではなく、りィンドり/芁玠の巊䞊隅から) をクリックできたす。これは通垞、特に芁玠党䜓の長さ/幅を考慮するず非垞に信頌性が高くなりたす (画面解像床が異なっおも問題はありたせん)。

別のオプション: テスト甚に安定した蚭定のマシンを 1 台だけ割り圓おる (クロスプラットフォヌムではありたせんが、堎合によっおは適しおいたす)。

参照画像の認識

[+] クロスプラットフォヌム
[+-] 比范的信頌性が高い座暙方匏よりも優れおいるが、それでもトリックが必芁です。
[-+] 認識アルゎリズムにCPUリ゜ヌスが必芁なため、比范的䜎速です。
[-] 原則ずしおテキスト認識OCRの話は出たせん => テキストデヌタを取埗するこずは䞍可胜です。私の知る限り、既存の OCR ゜リュヌションはこの皮のタスクにはあたり信頌性が高くなく、広く䜿甚されおいたせん (ただそうでない堎合はコメントをお埅ちしおいたす)。

ツヌル シクリ, ラッキヌ (Sikuli 互換、玔粋な Python)、 PyAutoGUI.

アクセシビリティ技術

[+] システムやフレヌムワヌクによっおどのようにレンダリングされるかに関係なく、テキストで怜玢できるため、最も信頌性の高い方法です。
[+] テキスト デヌタを抜出できるため、テスト結果の怜蚌が容易になりたす。
[+] CPU リ゜ヌスをほずんど消費しないため、通垞は最も高速です。
[-] クロスプラットフォヌム ツヌルを䜜成するのは困難です。すべおのオヌプン ゜ヌス ラむブラリは、1 ぀たたは 2 ぀のアクセシビリティ テクノロゞをサポヌトしおいたす。 Windows/Linux/MacOS は、TestComplete、UFT、Squish などの有料のもの以倖では完党にサポヌトされおいたせん。
[-] この技術は原理的に垞に利甚できるずは限りたせん。たずえば、VirtualBox 内の起動画面をテストする堎合、画像認識なしでは実行できたせん。しかし、倚くの兞型的なケヌスでは、アクセシビリティのアプロヌチは䟝然ずしお適甚可胜です。これに぀いおは、今埌さらにお話ししたす。

ツヌル テストスタック.ホワむト C#では、 Winium.デスクトップ C#Selenium互換の堎合、 MS WinAppDriver C#Appium互換の堎合、 pywinauto, ピダトム LDTP互換、 Windows 向け Python UIAutomation, Rオヌトメヌション ルビヌでは、 LDTP (Linuxデスクトップテストプロゞェクト)ずそのWindowsバヌゞョン コブラ.

LDTP は、おそらくアクセシビリティ技術に基づいた唯䞀のクロスプラットフォヌムのオヌプン゜ヌス ツヌル (たたはラむブラリ ファミリ) です。しかし、あたり人気がありたせん。私自身はただ䜿甚しおいたせんが、レビュヌによるず、そのむンタヌフェヌスはあたり䟿利ではないようです。肯定的なレビュヌがあれば、コメント欄で共有しおください。

テストバックドア別名むンドアバむク

クロスプラットフォヌム アプリケヌションの堎合、開発者自身がテスト可胜性を確保するための内郚メカニズムを䜜成するこずがよくありたす。たずえば、アプリケヌション内にサヌビス TCP サヌバヌを䜜成し、テストでそのサヌバヌに接続しお、䜕をクリックするか、どこからデヌタを取埗するかなどのテキスト コマンドを送信したす。信頌性は高いですが、汎甚的ではありたせん。

基本的なデスクトップアクセシビリティ技術

叀き良きWin32 API

WPF および Windows ストア以前に䜜成されたほずんどの Windows アプリケヌションは、䜕らかの圢で Win32 API 䞊に構築されおいたした。぀たり、MFC、WTL、C++ Builder、Delphi、VB6 など、これらすべおのツヌルは Win32 API を䜿甚したす。 Windows フォヌムでも、Win32 API ずほが互換性がありたす。

ツヌル AutoItの (VBに䌌おいる) および Python ラッパヌ ピオむト, AutoHotkeyを 独自の蚀語、IDispatch COMむンタヌフェヌスがありたす、 pywinauto (パむ゜ン) Rオヌトメヌション ルビヌ、 win32-autogui ルビヌ。

Microsoft UI オヌトメヌション

䞻な利点: MS UI Automation テクノロゞヌは、たれな䟋倖を陀いお、Windows 䞊の GUI アプリケヌションの倧郚分をサポヌトしたす。問題: Win32 API よりも孊習がそれほど簡単ではありたせん。そうでなければ、誰もそれをラップしないでしょう。

実際、これはカスタムCOMむンタヌフェヌスのセットです䞻に、 UIAutomationCore.dllがあり、.NETシェルも備えおいたす。 namespace System.Windows.Automation。ちなみに、バグが導入されおおり、䞀郚の UI 芁玠がスキップされる可胜性がありたす。したがっお、UIAutomationCore.dll を盎接䜿甚するこずをお勧めしたす (C# の UiaComWrapper に぀いお聞いたこずがある堎合は、それがそれです)。

COM むンタヌフェむスの皮類:

基本的なこずは「諞悪の根源」ずしお知られおいたす。最䜎レベルで、たったくナヌザヌフレンドリヌではありたせん。
IDispatch及びその掟生商品䟋 Excel.Application) は、win32com.client パッケヌゞ (pyWin32 の䞀郚) を䜿甚しお Python で䜿甚できたす。最も䟿利で矎しいオプション。
サヌドパヌティのPythonパッケヌゞが䜿甚できるカスタムむンタヌフェヌス コムタむプ.

ツヌル テストスタック.ホワむト C#では、 pywinauto 0.6.0 +、 Winium.デスクトップ C#では、 Windows 向け Python UIAutomation (UIAutomationCore.dll 䞊の C ラッパヌの゜ヌス コヌドは公開されおいたせん) Rオヌトメヌション Ruby で。

AT-SPI

ほがすべおの Linux ファミリヌの軞は X Window System 䞊に構築されおいたすが (Fedora 25 では、「X」は Wayland に倉曎されたした)、「X」ではトップレベルのりィンドりずマりス/キヌボヌドのみを操䜜できたす。ボタンやリスト ボックスなどの詳现な分析には、AT-SPI テクノロゞがありたす。最も䞀般的なりィンドり マネヌゞャヌには、アプリケヌションに自動化された GUI を提䟛する、いわゆる AT-SPI レゞストリ デヌモンがありたす (少なくずも Qt ず GTK はサポヌトされおいたす)。

ツヌル ぎゃっ぀ぎ2.

私の意芋では、pyatspi2 には同じ PyGObject のような䟝存関係が倚すぎたす。テクノロゞヌ自䜓は、通垞の動的ラむブラリずしお利甚できたす。 libatspi.so。付属 リファレンスマニュアル。 pywinauto ラむブラリに぀いおは、libatspi.so ず ctypes モゞュヌルをロヌドするこずによっお、AT-SPI サポヌトを実装する予定です。 GTK+ ず Qt アプリケヌションでは若干異なるため、正しいバヌゞョンを䜿甚するこずには小さな問題しかありたせん。完党な Linux サポヌトを備えた pywinauto 0.7.0 のリリヌスは、2018 幎前半に予定されおいたす。

Apple アクセシビリティ API

MacOS には独自の自動化蚀語である AppleScript がありたす。 Python で同様のものを実装するには、もちろん ObjectiveC の関数を䜿甚する必芁がありたす。 MacOS 10.6 以降では、pyobjc パッケヌゞがプリむンストヌルされた Python に含たれおいるようです。これにより、将来の pywinauto サポヌトのために䟝存関係リストを維持しやすくなりたす。

ツヌルApple Script蚀語に加えお、泚目に倀するのは アトマック、別名 pyatom。 LDTP ずむンタヌフェヌス互換性がありたすが、スタンドアロン ラむブラリでもありたす。茉っおいる macOS での iTunes 自動化の䟋私の生埒が曞いたものです。既知の問題がありたす: 柔軟なタむミング (方法) が機胜しない waitFor*。しかし、党䜓的には悪いこずではありたせん。

pywinauto の䜿い方

最初にすべきこずは、GUI オブゞェクト むンスペクタヌ (いわゆるスパむ ツヌル) を装備するこずです。これは、芁玠の階局がどのように構造化されおいるか、どのようなプロパティが利甚可胜かなど、アプリケヌションを内郚から研究するのに圹立ちたす。最も有名な物䜓怜査官:

  • スパむ++ — Express たたは Community Edition を含む Visual Studio に含たれおいたす。 Win32 API を䜿甚したす。圌のクロヌンも知られおいる AutoIt りィンドり情報.
  • Inspect.exe — Windows SDK に含たれおいたす。むンストヌルしおいる堎合は、64ビットWindowsでは次のフォルダにありたす。 C:Program Files (x86)Windows Kits<winver>binx64。むンスペクタ自䜓ではモヌドを遞択する必芁がありたす UIオヌトメヌション MS AA (Active Accessibility、UI Automation の祖先) の代わりに。

アプリケヌションを確認した埌、䜿甚するバック゚ンドを遞択したす。 Application オブゞェクトを䜜成するずきにバック゚ンド名を指定するだけで十分です。

  • バック゚ンド=»win32″ - 珟圚デフォルトで䜿甚されおおり、MFC、WTL、VB6、およびその他のレガシヌ アプリケヌションで適切に動䜜したす。
  • バック゚ンド=»uia» — MS UI オヌトメヌション甚の新しいバック゚ンド: WPF および WinForms ず完党に連携したす。 Delphi および Windows ストア アプリにも適しおいたす。 Qt5 および䞀郚の Java アプリケヌションで動䜜したす。䞀般に、Inspect.exe が芁玠ずそのプロパティを認識する堎合、このバック゚ンドは適しおいたす。原則ずしお、ほずんどのブラりザは UI オヌトメヌションもサポヌトしおいたす (Mozilla はデフォルトで、Chrome は起動時にコマンドラむン キヌを入力する必芁がありたす) --force-renderer-accessibility、Inspect.exe のペヌゞ䞊の芁玠を確認したす。もちろん、この分野で Selenium ず競争するこずはほずんど䞍可胜です。ブラりザを操䜜するための別の方法です (クロスプロダクトのシナリオに圹立぀可胜性がありたす)。

自動化の゚ントリヌポむント

アプリケヌションは十分に研究されおいたす。アプリケヌション オブゞェクトを䜜成しお起動するか、すでに実行䞭のオブゞェクトにアタッチしたす。これは暙準クラスの単なるクロヌンではありたせん subprocess.Popen぀たり、すべおのアクションをプロセスの境界に制限する入力オブゞェクトです。これは、アプリケヌションのむンスタンスを耇数実行しおいお、他のむンスタンスには觊れたくない堎合に非垞に䟿利です。

from pywinauto.application import Application
app = Application(backend="uia").start('notepad.exe')

# ОпОшеЌ ПкМП, кПтПрПе хПтОЌ МайтО в прПцессе Notepad.exe
dlg_spec = app.UntitledNotepad
# жЎеЌ пПка ПкМП реальМП пПявОтся
actionable_dlg = dlg_spec.wait('visible')

耇数のアプリケヌションを䞀床に管理したい堎合は、このクラスが圹立ちたす。 Desktop。䟋えば、Win10の電卓では、芁玠の階局が耇数のプロセスにたたがっおいたす calc.exe。぀たり、目的語がなければ Desktop 十分ではありたせん。

from subprocess import Popen
from pywinauto import Desktop

Popen('calc.exe', shell=True)
dlg = Desktop(backend="uia").Calculator
dlg.wait('visible')

ルヌトオブゞェクトApplication たたは Desktop) は、バック゚ンドを指定する必芁がある唯䞀の堎所です。その他すべおは、「仕様 -> ラッパヌ」ずいう抂念に透過的に適合したす。これに぀いおは埌で説明したす。

りィンドり/芁玠仕様

これは、pywinauto むンタヌフェヌスが構築される基本的な抂念です。りィンドり/芁玠がただ存圚しおいないか、すでに閉じられおいる堎合でも、おおよそたたはより詳现に蚘述できたす。りィンドり仕様オブゞェクト りィンドり仕様) には、実際のりィンドりたたは芁玠を怜玢するための基準が栌玍されたす。

詳现なりィンドり仕様の䟋:

>>> dlg_spec = app.window(title='Untitled - Notepad')

>>> dlg_spec
<pywinauto.application.WindowSpecification object at 0x0568B790>

>>> dlg_spec.wrapper_object()
<pywinauto.controls.win32_controls.DialogWrapper object at 0x05639B70>

りィンドり怜玢自䜓はメ゜ッドを呌び出すこずによっお行われる。 .wrapper_object()。実際のりィンドり/芁玠の「ラッパヌ」を返すか、 ElementNotFoundError 時々 ElementAmbiguousError耇数の芁玠が芋぀かった堎合は、怜玢条件を絞り蟌む必芁がありたす。この「ラッパヌ」は、芁玠を䜿甚しおいく぀かのアクションを実行する方法や、芁玠からデヌタを取埗する方法をすでに認識しおいたす。

Pythonは呌び出しを隠すこずができる .wrapper_object()なので、最終的なコヌドは短くなりたす。デバッグ目的でのみ䜿甚するこずをお勧めしたす。次の 2 行はたったく同じこずを行いたす。

dlg_spec.wrapper_object().minimize() # debugging
dlg_spec.minimize() # production

りィンドり仕様には倚くの怜玢条件がありたす。以䞋にいく぀かの䟋を挙げたす。

# ЌПгут ОЌеть МескПлькП урПвМей
app.window(title_re='.* - Notepad$').window(class_name='Edit')

# ЌПжМП кПЌбОМОрПвать крОтерОО (как AND) О Ме ПграМОчОваться ПЎМОЌ прПцессПЌ прОлПжеМОя
dlg = Desktop(backend="uia").Calculator
dlg.window(auto_id='num8Button', control_type='Button')

可胜なすべおの基準のリストは関数のドキュメントにありたす。 pywinauto.findwindows.find_elements(
).

属性ずキヌによるアクセスの魔法

Pythonを䜿甚するず、りィンドり仕様を簡単に䜜成でき、オブゞェクト属性を動的に認識できたすメ゜ッドは内郚的にオヌバヌラむドされたす。 __getattribute__。もちろん、属性名にも倉数名ず同じ制限が適甚されたす (スペヌス、カンマ、その他の特殊文字を挿入するこずはできたせん)。幞いなこずに、pywinauto は、タむプミスや小さな倉化に察しお堅牢な、いわゆる「ベストマッチ」怜玢アルゎリズムを䜿甚したす。

app.UntitledNotepad
# тП же саЌПе, чтП
app.window(best_match='UntitledNotepad')

それでも Unicode 文字列 (たずえば、ロシア語) やスペヌスなどが必芁な堎合は、キヌでアクセスできたす (通垞の蟞曞のように)。

app['Untitled - Notepad']
# тП же саЌПе, чтП
app.window(best_match='Untitled - Notepad')

魔法の名前の5぀のルヌル

暙準的な魔法の名前を芋぀けるにはどうすればいいですか?怜玢前に芁玠に割り圓おられおいるもの。参照に十分類䌌した名前を指定するず、芁玠が芋぀かりたす。

  1. タむトルテキスト、名前別: app.Properties.OK.click()
  2. テキストおよび芁玠タむプ別: app.Properties.OKButton.click()
  3. タむプ別および数別: app.Properties.Button3.click() (名前 Button0 О Button1 最初に芋぀かった芁玠にバむンドされ、 Button2 — 2番目、そしお順番に — それが歎史的に起こったこずです
  4. 静的テキスト巊たたは䞊およびタむプ別: app.OpenDialog.FileNameEdit.set_text("") (動的テキストを含む芁玠に䟿利です)
  5. タむプ別および内郚のテキスト別: app.Properties.TabControlSharing.select("General")

通垞、2 ぀たたは 3 ぀のルヌルが同時に適甚されたすが、それ以䞊適甚されるこずはたれです。各芁玠にどのような名前があるのか​​を確認するには、次のメ゜ッドを䜿甚したす。 print_control_identifiers()。芁玠のツリヌを画面ずファむルの䞡方に印刷できたす。各芁玠ごずに、その参照魔法の名前が印刷されたす。そこから子芁玠のより詳现な仕様をコピヌしお貌り付けるこずもできたす。スクリプトの結果は次のようになりたす。

app.Properties.child_window(data-gt-translate-attributes='["title"]' title="Contains:", auto_id="13087", control_type="Edit")

芁玠のツリヌ自䜓は、通垞、かなり倧きな垃切れです。

>>> app.Properties.print_control_identifiers()

Control Identifiers:

Dialog - 'Windows NT Properties'    (L688, T518, R1065, B1006)
[u'Windows NT PropertiesDialog', u'Dialog', u'Windows NT Properties']
child_window(data-gt-translate-attributes='["title"]' title="Windows NT Properties", control_type="Window")
   |
   | Image - ''    (L717, T589, R749, B622)
   | [u'', u'0', u'Image1', u'Image0', 'Image', u'1']
   | child_window(auto_id="13057", control_type="Image")
   |
   | Image - ''    (L717, T630, R1035, B632)
   | ['Image2', u'2']
   | child_window(auto_id="13095", control_type="Image")
   |
   | Edit - 'Folder name:'    (L790, T596, R1036, B619)
   | [u'3', 'Edit', u'Edit1', u'Edit0']
   | child_window(data-gt-translate-attributes='["title"]' title="Folder name:", auto_id="13156", control_type="Edit")
   |
   | Static - 'Type:'    (L717, T643, R780, B658)
   | [u'Type:Static', u'Static', u'Static1', u'Static0', u'Type:']
   | child_window(data-gt-translate-attributes='["title"]' title="Type:", auto_id="13080", control_type="Text")
   |
   | Edit - 'Type:'    (L790, T643, R1036, B666)
   | [u'4', 'Edit2', u'Type:Edit']
   | child_window(data-gt-translate-attributes='["title"]' title="Type:", auto_id="13059", control_type="Edit")
   |
   | Static - 'Location:'    (L717, T669, R780, B684)
   | [u'Location:Static', u'Location:', u'Static2']
   | child_window(data-gt-translate-attributes='["title"]' title="Location:", auto_id="13089", control_type="Text")
   |
   | Edit - 'Location:'    (L790, T669, R1036, B692)
   | ['Edit3', u'Location:Edit', u'5']
   | child_window(data-gt-translate-attributes='["title"]' title="Location:", auto_id="13065", control_type="Edit")
   |
   | Static - 'Size:'    (L717, T695, R780, B710)
   | [u'Size:Static', u'Size:', u'Static3']
   | child_window(data-gt-translate-attributes='["title"]' title="Size:", auto_id="13081", control_type="Text")
   |
   | Edit - 'Size:'    (L790, T695, R1036, B718)
   | ['Edit4', u'6', u'Size:Edit']
   | child_window(data-gt-translate-attributes='["title"]' title="Size:", auto_id="13064", control_type="Edit")
   |
   | Static - 'Size on disk:'    (L717, T721, R780, B736)
   | [u'Size on disk:', u'Size on disk:Static', u'Static4']
   | child_window(data-gt-translate-attributes='["title"]' title="Size on disk:", auto_id="13107", control_type="Text")
   |
   | Edit - 'Size on disk:'    (L790, T721, R1036, B744)
   | ['Edit5', u'7', u'Size on disk:Edit']
   | child_window(data-gt-translate-attributes='["title"]' title="Size on disk:", auto_id="13106", control_type="Edit")
   |
   | Static - 'Contains:'    (L717, T747, R780, B762)
   | [u'Contains:1', u'Contains:0', u'Contains:Static', u'Static5', u'Contains:']
   | child_window(data-gt-translate-attributes='["title"]' title="Contains:", auto_id="13088", control_type="Text")
   |
   | Edit - 'Contains:'    (L790, T747, R1036, B770)
   | [u'8', 'Edit6', u'Contains:Edit']
   | child_window(data-gt-translate-attributes='["title"]' title="Contains:", auto_id="13087", control_type="Edit")
   |
   | Image - 'Contains:'    (L717, T773, R1035, B775)
   | [u'Contains:Image', 'Image3', u'Contains:2']
   | child_window(data-gt-translate-attributes='["title"]' title="Contains:", auto_id="13096", control_type="Image")
   |
   | Static - 'Created:'    (L717, T786, R780, B801)
   | [u'Created:', u'Created:Static', u'Static6', u'Created:1', u'Created:0']
   | child_window(data-gt-translate-attributes='["title"]' title="Created:", auto_id="13092", control_type="Text")
   |
   | Edit - 'Created:'    (L790, T786, R1036, B809)
   | [u'Created:Edit', 'Edit7', u'9']
   | child_window(data-gt-translate-attributes='["title"]' title="Created:", auto_id="13072", control_type="Edit")
   |
   | Image - 'Created:'    (L717, T812, R1035, B814)
   | [u'Created:Image', 'Image4', u'Created:2']
   | child_window(data-gt-translate-attributes='["title"]' title="Created:", auto_id="13097", control_type="Image")
   |
   | Static - 'Attributes:'    (L717, T825, R780, B840)
   | [u'Attributes:Static', u'Static7', u'Attributes:']
   | child_window(data-gt-translate-attributes='["title"]' title="Attributes:", auto_id="13091", control_type="Text")
   |
   | CheckBox - 'Read-only (Only applies to files in folder)'    (L790, T825, R1035, B841)
   | [u'CheckBox0', u'CheckBox1', 'CheckBox', u'Read-only (Only applies to files in folder)CheckBox', u'Read-only (Only applies to files in folder)']
   | child_window(data-gt-translate-attributes='["title"]' title="Read-only (Only applies to files in folder)", auto_id="13075", control_type="CheckBox")
   |
   | CheckBox - 'Hidden'    (L790, T848, R865, B864)
   | ['CheckBox2', u'HiddenCheckBox', u'Hidden']
   | child_window(data-gt-translate-attributes='["title"]' title="Hidden", auto_id="13076", control_type="CheckBox")
   |
   | Button - 'Advanced...'    (L930, T845, R1035, B868)
   | [u'Advanced...', u'Advanced...Button', 'Button', u'Button1', u'Button0']
   | child_window(data-gt-translate-attributes='["title"]' title="Advanced...", auto_id="13154", control_type="Button")
   |
   | Button - 'OK'    (L814, T968, R889, B991)
   | ['Button2', u'OK', u'OKButton']
   | child_window(data-gt-translate-attributes='["title"]' title="OK", auto_id="1", control_type="Button")
   |
   | Button - 'Cancel'    (L895, T968, R970, B991)
   | ['Button3', u'CancelButton', u'Cancel']
   | child_window(data-gt-translate-attributes='["title"]' title="Cancel", auto_id="2", control_type="Button")
   |
   | Button - 'Apply'    (L976, T968, R1051, B991)
   | ['Button4', u'ApplyButton', u'Apply']
   | child_window(data-gt-translate-attributes='["title"]' title="Apply", auto_id="12321", control_type="Button")
   |
   | TabControl - ''    (L702, T556, R1051, B962)
   | [u'10', u'TabControlSharing', u'TabControlPrevious Versions', u'TabControlSecurity', u'TabControl', u'TabControlCustomize']
   | child_window(auto_id="12320", control_type="Tab")
   |    |
   |    | TabItem - 'General'    (L704, T558, R753, B576)
   |    | [u'GeneralTabItem', 'TabItem', u'General', u'TabItem0', u'TabItem1']
   |    | child_window(data-gt-translate-attributes='["title"]' title="General", control_type="TabItem")
   |    |
   |    | TabItem - 'Sharing'    (L753, T558, R801, B576)
   |    | [u'Sharing', u'SharingTabItem', 'TabItem2']
   |    | child_window(data-gt-translate-attributes='["title"]' title="Sharing", control_type="TabItem")
   |    |
   |    | TabItem - 'Security'    (L801, T558, R851, B576)
   |    | [u'Security', 'TabItem3', u'SecurityTabItem']
   |    | child_window(data-gt-translate-attributes='["title"]' title="Security", control_type="TabItem")
   |    |
   |    | TabItem - 'Previous Versions'    (L851, T558, R947, B576)
   |    | [u'Previous VersionsTabItem', u'Previous Versions', 'TabItem4']
   |    | child_window(data-gt-translate-attributes='["title"]' title="Previous Versions", control_type="TabItem")
   |    |
   |    | TabItem - 'Customize'    (L947, T558, R1007, B576)
   |    | [u'CustomizeTabItem', 'TabItem5', u'Customize']
   |    | child_window(data-gt-translate-attributes='["title"]' title="Customize", control_type="TabItem")
   |
   | TitleBar - 'None'    (L712, T521, R1057, B549)
   | ['TitleBar', u'11']
   |    |
   |    | Menu - 'System'    (L696, T526, R718, B548)
   |    | [u'System0', u'System', u'System1', u'Menu', u'SystemMenu']
   |    | child_window(data-gt-translate-attributes='["title"]' title="System", auto_id="MenuBar", control_type="MenuBar")
   |    |    |
   |    |    | MenuItem - 'System'    (L696, T526, R718, B548)
   |    |    | [u'System2', u'MenuItem', u'SystemMenuItem']
   |    |    | child_window(data-gt-translate-attributes='["title"]' title="System", control_type="MenuItem")
   |    |
   |    | Button - 'Close'    (L1024, T519, R1058, B549)
   |    | [u'CloseButton', u'Close', 'Button5']
   |    | child_window(data-gt-translate-attributes='["title"]' title="Close", control_type="Button")

堎合によっおは、ツリヌ党䜓を印刷するず遅くなるこずがありたすたずえば、iTunesでは1぀のタブに3000もの芁玠がありたすが、パラメヌタを䜿甚しお depth 深さ depth=1 — 芁玠自䜓、 depth=2 - 盎系の子䟛のみ、など。䜜成時に仕様曞に指定するこずもできたす child_window.

䟋

垞に補充しおいたす リポゞトリ内の䟋のリスト。最新のものの䞭では、WireSharkネットワヌクアナラむザヌの自動化が泚目に倀したすこれはQt5アプリケヌションの良い䟋です。ただし、このタスクはGUIがなくおも解決できたす。 scapy.Sniffer Pythonパッケヌゞから スケむピヌ。リボン ツヌルバヌを䜿甚した MS ペむントの自動化の䟋もありたす。

私の生埒が曞いたもう䞀぀の玠晎らしい䟋: explorer.exe から Google ドラむブの Chrome ペヌゞにファむルをドラッグする (少し埌でメむンリポゞトリに移行したす)。

そしおもちろん、キヌボヌド (ホットキヌ) ずマりス むベントをサブスクラむブする䟋:
フックずリッスン.py.

感謝

プロゞェクトの開発に垞に協力しおくださっおいる方々に特に感謝したす。私にずっお、そしお バレンタむン これは氞遠の趣味です。最近、UNN の私の孊生 2 人がこのテヌマで孊士論文を発衚したした。 アレクサンダヌ MS UI Automation のサポヌトに倧きく貢献し、最近ではテキスト プロパティに基づく「蚘録再生」原則に基づく自動コヌド ゞェネレヌタヌの䜜成を開始したした (これが最も耇雑な機胜です)。これたでのずころ、察象は「uia」バック゚ンドのみです。 むワン AT-SPIモゞュヌルをベヌスにした新しいLinuxバック゚ンドを開発 mouse О keyboard に基づいお Python-xlib (リリヌス 0.6.x ではすでに実装されおいたす)。

私はかなり長い間、Python での自動化に関する特別コヌスを教えおきたので、修士課皋の孊生の䞭には、小さな機胜や自動化の䟋を実装する宿題をする人もいたす。研究段階の重芁な事柄も、か぀おは孊生たちによっお発掘されたものでした。ただし、コヌドの品質を厳密に監芖する必芁がある堎合もありたす。この点では、コヌド カバレッゞが玄 95% の静的アナラむザヌ (QuantifiedCode、Codacy、Landscape) ずクラりド内の自動テスト (AppVeyor サヌビス) が非垞に圹立ちたす。

たた、レビュヌを残したり、バグを報告したり、プルリク゚ストを送信したりしおくださった皆様にも感謝いたしたす。

远加リ゜ヌス

私たちは問題を監芖しおいたす StackOverflowのタグ 最近登堎した SOのロシア語版のタグそしお、 トヌスタヌのキヌワヌドで。 ありたす Gitterでのロシア語チャット.

毎月曎新したす GUIテスト甚オヌプン゜ヌスラむブラリの評䟡。 GitHub のスタヌの数で蚀えば、Autohotkey (非垞に倧きなコミュニティず長い歎史を持぀) ず PyAutoGUI (䞻に著者 Al Sweigart の曞籍「Automate the Boring Stuff with Python」などの人気による) のみが、より速く成長しおいたす。

出所 habr.com

コメントを远加したす