АвтоматизируСм дСсктопный GUI Π½Π° Python + pywinauto: ΠΊΠ°ΠΊ ΠΏΠΎΠ΄Ρ€ΡƒΠΆΠΈΡ‚ΡŒΡΡ c MS UI Automation

Python Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° pywinauto β€” это open source ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ ΠΏΠΎ Π°Π²Ρ‚ΠΎΠΌΠ°Ρ‚ΠΈΠ·Π°Ρ†ΠΈΠΈ дСсктопных GUI ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ Π½Π° Windows. Π—Π° послСдниС Π΄Π²Π° Π³ΠΎΠ΄Π° Π² Π½Π΅ΠΉ появились Π½ΠΎΠ²Ρ‹Π΅ ΠΊΡ€ΡƒΠΏΠ½Ρ‹Π΅ Ρ„ΠΈΡ‡ΠΈ:

  • ΠŸΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠ° Ρ‚Π΅Ρ…Π½ΠΎΠ»ΠΎΠ³ΠΈΠΈ MS UI Automation. Π˜Π½Ρ‚Π΅Ρ€Ρ„Π΅ΠΉΡ ΠΏΡ€Π΅ΠΆΠ½ΠΈΠΉ, ΠΈ Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°ΡŽΡ‚ΡΡ: WinForms, WPF, Qt5, Windows Store (UWP) ΠΈ Ρ‚Π°ΠΊ Π΄Π°Π»Π΅Π΅ β€” ΠΏΠΎΡ‡Ρ‚ΠΈ всС, Ρ‡Ρ‚ΠΎ Π΅ΡΡ‚ΡŒ Π½Π° Windows.
  • БистСма бэкСндов/ΠΏΠ»Π°Π³ΠΈΠ½ΠΎΠ² (сСйчас ΠΈΡ… Π΄Π²ΠΎΠ΅ ΠΏΠΎΠ΄ ΠΊΠ°ΠΏΠΎΡ‚ΠΎΠΌ: Π΄Π΅Ρ„ΠΎΠ»Ρ‚Π½Ρ‹ΠΉ "win32" ΠΈ Π½ΠΎΠ²Ρ‹ΠΉ "uia"). Π”Π°Π»ΡŒΡˆΠ΅ ΠΏΠ»Π°Π²Π½ΠΎ двигаСмся Π² сторону кросс-платформСнности.
  • Win32 Ρ…ΡƒΠΊΠΈ для ΠΌΡ‹ΡˆΠΈ ΠΈ ΠΊΠ»Π°Π²ΠΈΠ°Ρ‚ΡƒΡ€Ρ‹ (hot keys Π² Π΄ΡƒΡ…Π΅ pyHook).

Π’Π°ΠΊΠΆΠ΅ сдСлаСм нСбольшой ΠΎΠ±Π·ΠΎΡ€ Ρ‚ΠΎΠ³ΠΎ, Ρ‡Ρ‚ΠΎ Π΅ΡΡ‚ΡŒ Π² open source для дСсктопной Π°Π²Ρ‚ΠΎΠΌΠ°Ρ‚ΠΈΠ·Π°Ρ†ΠΈΠΈ (Π±Π΅Π· ΠΏΡ€Π΅Ρ‚Π΅Π½Π·ΠΈΠΉ Π½Π° ΡΠ΅Ρ€ΡŒΠ΅Π·Π½ΠΎΠ΅ сравнСниС).

Π­Ρ‚Π° ΡΡ‚Π°Ρ‚ΡŒΡ β€” частично Ρ€Π°ΡΡˆΠΈΡ„Ρ€ΠΎΠ²ΠΊΠ° Π΄ΠΎΠΊΠ»Π°Π΄Π° с ΠΊΠΎΠ½Ρ„Π΅Ρ€Π΅Π½Ρ†ΠΈΠΈ SQA Days 20 Π² МинскС (видСозапись ΠΈ слайды), частично русская вСрсия Getting Started Guide для pywinauto.

Начнём с ΠΊΡ€Π°Ρ‚ΠΊΠΎΠ³ΠΎ ΠΎΠ±Π·ΠΎΡ€Π° ΠΎΠΏΠ΅Π½ сорса Π² этой области. Для дСсктопных GUI ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ всё нСсколько слоТнСС, Ρ‡Π΅ΠΌ для Π²Π΅Π±Π°, Ρƒ ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ³ΠΎ Π΅ΡΡ‚ΡŒ Selenium. Π’ΠΎΡ‚ основныС ΠΏΠΎΠ΄Ρ…ΠΎΠ΄Ρ‹:

ΠšΠΎΠΎΡ€Π΄ΠΈΠ½Π°Ρ‚Π½Ρ‹ΠΉ ΠΌΠ΅Ρ‚ΠΎΠ΄

Π₯Π°Ρ€Π΄ΠΊΠΎΠ΄ΠΈΠΌ Ρ‚ΠΎΡ‡ΠΊΠΈ ΠΊΠ»ΠΈΠΊΠΎΠ², надССмся Π½Π° ΡƒΠ΄Π°Ρ‡Π½Ρ‹Π΅ попадания.
[+] ΠšΡ€ΠΎΡΡ-ΠΏΠ»Π°Ρ‚Ρ„ΠΎΡ€ΠΌΠ΅Π½Π½Ρ‹ΠΉ, Π»Π΅Π³ΠΊΠΎ Ρ€Π΅Π°Π»ΠΈΠ·ΡƒΠ΅ΠΌΡ‹ΠΉ.
[+] Π›Π΅Π³ΠΊΠΎ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ «record-replay» запись тСстов.
[-] Π‘Π°ΠΌΡ‹ΠΉ Π½Π΅ΡΡ‚Π°Π±ΠΈΠ»ΡŒΠ½Ρ‹ΠΉ ΠΊ измСнСнию Ρ€Π°Π·Ρ€Π΅ΡˆΠ΅Π½ΠΈΡ экрана, Ρ‚Π΅ΠΌΡ‹, ΡˆΡ€ΠΈΡ„Ρ‚ΠΎΠ², Ρ€Π°Π·ΠΌΠ΅Ρ€ΠΎΠ² ΠΎΠΊΠΎΠ½ ΠΈ Ρ‚.ΠΏ.
[-] НуТны ΠΎΠ³Ρ€ΠΎΠΌΠ½Ρ‹Π΅ усилия Π½Π° ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΡƒ, часто ΠΏΡ€ΠΎΡ‰Π΅ ΠΏΠ΅Ρ€Π΅Π³Π΅Π½Π΅Ρ€ΠΈΡ‚ΡŒ тСсты с нуля ΠΈΠ»ΠΈ Ρ‚Π΅ΡΡ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Π²Ρ€ΡƒΡ‡Π½ΡƒΡŽ.
[-] АвтоматизируСт Ρ‚ΠΎΠ»ΡŒΠΊΠΎ дСйствия, для Π²Π΅Ρ€ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΠΈ ΠΈ извлСчСния Π΄Π°Π½Π½Ρ‹Ρ… Π΅ΡΡ‚ΡŒ Π΄Ρ€ΡƒΠ³ΠΈΠ΅ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹.

Π˜Π½ΡΡ‚Ρ€ΡƒΠΌΠ΅Π½Ρ‚Ρ‹ (кросс-ΠΏΠ»Π°Ρ‚Ρ„ΠΎΡ€ΠΌΠ΅Π½Π½Ρ‹Π΅): autopy, PyAutoGUI, PyUserInput ΠΈ ΠΌΠ½ΠΎΠ³ΠΈΠ΅ Π΄Ρ€ΡƒΠ³ΠΈΠ΅. Как ΠΏΡ€Π°Π²ΠΈΠ»ΠΎ, Π±ΠΎΠ»Π΅Π΅ слоТныС инструмСнты Π²ΠΊΠ»ΡŽΡ‡Π°ΡŽΡ‚ Π² сСбя эту Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ (Π½Π΅ всСгда кросс-ΠΏΠ»Π°Ρ‚Ρ„ΠΎΡ€ΠΌΠ΅Π½Π½ΠΎ).

Π‘Ρ‚ΠΎΠΈΡ‚ ΡΠΊΠ°Π·Π°Ρ‚ΡŒ, Ρ‡Ρ‚ΠΎ ΠΊΠΎΠΎΡ€Π΄ΠΈΠ½Π°Ρ‚Π½Ρ‹ΠΉ ΠΌΠ΅Ρ‚ΠΎΠ΄ ΠΌΠΎΠΆΠ΅Ρ‚ Π΄ΠΎΠΏΠΎΠ»Π½ΡΡ‚ΡŒ ΠΎΡΡ‚Π°Π»ΡŒΠ½Ρ‹Π΅ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄Ρ‹. НапримСр, для кастомной Π³Ρ€Π°Ρ„ΠΈΠΊΠΈ ΠΌΠΎΠΆΠ½ΠΎ ΠΊΠ»ΠΈΠΊΠ°Ρ‚ΡŒ ΠΏΠΎ ΠΎΡ‚Π½ΠΎΡΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹ΠΌ ΠΊΠΎΠΎΡ€Π΄ΠΈΠ½Π°Ρ‚Π°ΠΌ (ΠΎΡ‚ Π»Π΅Π²ΠΎΠ³ΠΎ Π²Π΅Ρ€Ρ…Π½Π΅Π³ΠΎ ΡƒΠ³Π»Π° ΠΎΠΊΠ½Π°/элСмСнта, Π° Π½Π΅ всСго экрана) β€” ΠΎΠ±Ρ‹Ρ‡Π½ΠΎ это достаточно Π½Π°Π΄Π΅ΠΆΠ½ΠΎ, особСнно Ссли ΡƒΡ‡ΠΈΡ‚Ρ‹Π²Π°Ρ‚ΡŒ Π΄Π»ΠΈΠ½Ρƒ/ΡˆΠΈΡ€ΠΈΠ½Ρƒ всСго элСмСнта (Ρ‚ΠΎΠ³Π΄Π° ΠΈ Ρ€Π°Π·Π½ΠΎΠ΅ Ρ€Π°Π·Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅ экрана Π½Π΅ ΠΏΠΎΠΌΠ΅ΡˆΠ°Π΅Ρ‚).

Π”Ρ€ΡƒΠ³ΠΎΠΉ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚: Π²Ρ‹Π΄Π΅Π»ΡΡ‚ΡŒ для тСстов Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΎΠ΄Π½Ρƒ ΠΌΠ°ΡˆΠΈΠ½Ρƒ со ΡΡ‚Π°Π±ΠΈΠ»ΡŒΠ½Ρ‹ΠΌΠΈ настройками (Π½Π΅ кросс-ΠΏΠ»Π°Ρ‚Ρ„ΠΎΡ€ΠΌΠ΅Π½Π½ΠΎ, Π½ΠΎ Π² ΠΊΠ°ΠΊΠΈΡ…-Ρ‚ΠΎ случаях годится).

РаспознаваниС эталонных ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΉ

[+] ΠšΡ€ΠΎΡΡ-ΠΏΠ»Π°Ρ‚Ρ„ΠΎΡ€ΠΌΠ΅Π½Π½Ρ‹ΠΉ
[+-] ΠžΡ‚Π½ΠΎΡΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ Π½Π°Π΄Π΅ΠΆΠ½Ρ‹ΠΉ (Π»ΡƒΡ‡ΡˆΠ΅, Ρ‡Π΅ΠΌ ΠΊΠΎΠΎΡ€Π΄ΠΈΠ½Π°Ρ‚Π½Ρ‹ΠΉ ΠΌΠ΅Ρ‚ΠΎΠ΄), Π½ΠΎ всё ΠΆΠ΅ Ρ‚Ρ€Π΅Π±ΡƒΠ΅Ρ‚ хитростСй.
[-+] ΠžΡ‚Π½ΠΎΡΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ ΠΌΠ΅Π΄Π»Π΅Π½Π½Ρ‹ΠΉ, Ρ‚.ΠΊ. Ρ‚Ρ€Π΅Π±ΡƒΠ΅Ρ‚ рСсурсов CPU для Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΠΌΠΎΠ² распознавания.
[-] О распознавании тСкста (OCR), ΠΊΠ°ΠΊ ΠΏΡ€Π°Π²ΠΈΠ»ΠΎ, Ρ€Π΅Ρ‡ΠΈ Π½Π΅ ΠΈΠ΄Ρ‘Ρ‚ => нСльзя Π΄ΠΎΡΡ‚Π°Ρ‚ΡŒ тСкстовыС Π΄Π°Π½Π½Ρ‹Π΅. Насколько ΠΌΠ½Π΅ извСстно, ΡΡƒΡ‰Π΅ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠ΅ OCR Ρ€Π΅ΡˆΠ΅Π½ΠΈΡ Π½Π΅ слишком Π½Π°Π΄Π΅ΠΆΠ½Ρ‹ для этого Ρ‚ΠΈΠΏΠ° Π·Π°Π΄Π°Ρ‡, ΠΈ ΡˆΠΈΡ€ΠΎΠΊΠΎΠ³ΠΎ примСнСния Π½Π΅ ΠΈΠΌΠ΅ΡŽΡ‚ (welcome Π² ΠΊΠΎΠΌΠΌΠ΅Π½Ρ‚Ρ‹, Ссли это ΡƒΠΆΠ΅ Π½Π΅ Ρ‚Π°ΠΊ).

Π˜Π½ΡΡ‚Ρ€ΡƒΠΌΠ΅Π½Ρ‚Ρ‹: Sikuli, Lackey (Sikuli-совмСстимый, Π½Π° чистом Python), PyAutoGUI.

Accessibility Ρ‚Π΅Ρ…Π½ΠΎΠ»ΠΎΠ³ΠΈΠΈ

[+] Π‘Π°ΠΌΡ‹ΠΉ Π½Π°Π΄Π΅ΠΆΠ½Ρ‹ΠΉ ΠΌΠ΅Ρ‚ΠΎΠ΄, Ρ‚.ΠΊ. позволяСт ΠΈΡΠΊΠ°Ρ‚ΡŒ ΠΏΠΎ тСксту, нСзависимо ΠΎΡ‚ Ρ‚ΠΎΠ³ΠΎ, ΠΊΠ°ΠΊ ΠΎΠ½ отрисован систСмой ΠΈΠ»ΠΈ Ρ„Ρ€Π΅ΠΉΠΌΠ²ΠΎΡ€ΠΊΠΎΠΌ.
[+] ΠŸΠΎΠ·Π²ΠΎΠ»ΡΠ΅Ρ‚ ΠΈΠ·Π²Π»Π΅ΠΊΠ°Ρ‚ΡŒ тСкстовыС Π΄Π°Π½Π½Ρ‹Π΅ => ΠΏΡ€ΠΎΡ‰Π΅ Π²Π΅Ρ€ΠΈΡ„ΠΈΡ†ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Ρ‹ тСстов.
[+] Как ΠΏΡ€Π°Π²ΠΈΠ»ΠΎ, самый быстрый, Ρ‚.ΠΊ. ΠΏΠΎΡ‡Ρ‚ΠΈ Π½Π΅ расходуСт рСсурсы CPU.
[-] ВяТСло ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ кросс-ΠΏΠ»Π°Ρ‚Ρ„ΠΎΡ€ΠΌΠ΅Π½Π½Ρ‹ΠΉ инструмСнт: Π°Π±ΡΠΎΠ»ΡŽΡ‚Π½ΠΎ всС open-source Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°ΡŽΡ‚ ΠΎΠ΄Π½Ρƒ-Π΄Π²Π΅ accessibility Ρ‚Π΅Ρ…Π½ΠΎΠ»ΠΎΠ³ΠΈΠΈ. Windows/Linux/MacOS Ρ†Π΅Π»ΠΈΠΊΠΎΠΌ Π½Π΅ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Π΅Ρ‚ Π½ΠΈΠΊΡ‚ΠΎ, ΠΊΡ€ΠΎΠΌΠ΅ ΠΏΠ»Π°Ρ‚Π½Ρ‹Ρ… Ρ‚ΠΈΠΏΠ° TestComplete, UFT ΠΈΠ»ΠΈ Squish.
[-] НС всСгда такая тСхнология Π² ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΠ΅ доступна. НапримСр, тСстированиС Π·Π°Π³Ρ€ΡƒΠ·ΠΎΡ‡Π½ΠΎΠ³ΠΎ экрана Π²Π½ΡƒΡ‚Ρ€ΠΈ VirtualBox’Π° β€” Ρ‚ΡƒΡ‚ Π±Π΅Π· распознавания ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΉ Π½Π΅ ΠΎΠ±ΠΎΠΉΡ‚ΠΈΡΡŒ. Но Π²ΠΎ ΠΌΠ½ΠΎΠ³ΠΈΡ… классичСских случаях всС-Ρ‚Π°ΠΊΠΈ accessibility ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ ΠΏΡ€ΠΈΠΌΠ΅Π½ΠΈΠΌ. О Π½Π΅ΠΌ дальшС ΠΈ ΠΏΠΎΠΉΠ΄Π΅Ρ‚ Ρ€Π΅Ρ‡ΡŒ.

Π˜Π½ΡΡ‚Ρ€ΡƒΠΌΠ΅Π½Ρ‚Ρ‹: TestStack.White Π½Π° C#, Winium.Desktop Π½Π° C# (Selenium совмСстимый), MS WinAppDriver Π½Π° C# (Appium совмСстимый), pywinauto, pyatom (совмСстим с LDTP), Python-UIAutomation-for-Windows, RAutomation Π½Π° Ruby, LDTP (Linux Desktop Testing Project) ΠΈ Π΅Π³ΠΎ Windows вСрсия Cobra.

LDTP β€” ΠΏΠΎΠΆΠ°Π»ΡƒΠΉ, СдинствСнный кросс-ΠΏΠ»Π°Ρ‚Ρ„ΠΎΡ€ΠΌΠ΅Π½Π½Ρ‹ΠΉ open-source инструмСнт (Ρ‚ΠΎΡ‡Π½Π΅Π΅ сСмСйство Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊ) Π½Π° основС accessibility Ρ‚Π΅Ρ…Π½ΠΎΠ»ΠΎΠ³ΠΈΠΉ. Однако ΠΎΠ½ Π½Π΅ слишком популярСн. Π‘Π°ΠΌ Π½Π΅ пользовался ΠΈΠΌ, Π½ΠΎ ΠΏΠΎ ΠΎΡ‚Π·Ρ‹Π²Π°ΠΌ интСрфСйс Ρƒ Π½Π΅Π³ΠΎ Π½Π΅ самый ΡƒΠ΄ΠΎΠ±Π½Ρ‹ΠΉ. Если Π΅ΡΡ‚ΡŒ ΠΏΠΎΠ·ΠΈΡ‚ΠΈΠ²Π½Ρ‹Π΅ ΠΎΡ‚Π·Ρ‹Π²Ρ‹, ΠΏΡ€ΠΎΡˆΡƒ ΠΏΠΎΠ΄Π΅Π»ΠΈΡ‚ΡŒΡΡ Π² ΠΊΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ….

ВСстовый backdoor (a.k.a. Π²Π½ΡƒΡ‚Ρ€Π΅Π½Π½ΠΈΠΉ вСлосипСд)

Для кросс-ΠΏΠ»Π°Ρ‚Ρ„ΠΎΡ€ΠΌΠ΅Π½Π½Ρ‹Ρ… ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ сами Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΈ часто Π΄Π΅Π»Π°ΡŽΡ‚ Π²Π½ΡƒΡ‚Ρ€Π΅Π½Π½ΠΈΠΉ ΠΌΠ΅Ρ…Π°Π½ΠΈΠ·ΠΌ для обСспСчСния testability. НапримСр, ΡΠΎΠ·Π΄Π°ΡŽΡ‚ слуТСбный TCP сСрвСр Π² ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΈ, тСсты ΠΊ Π½Π΅ΠΌΡƒ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°ΡŽΡ‚ΡΡ ΠΈ ΠΏΠΎΡΡ‹Π»Π°ΡŽΡ‚ тСкстовыС ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹: Π½Π° Ρ‡Ρ‚ΠΎ Π½Π°ΠΆΠ°Ρ‚ΡŒ, ΠΎΡ‚ΠΊΡƒΠ΄Π° Π²Π·ΡΡ‚ΡŒ Π΄Π°Π½Π½Ρ‹Π΅ ΠΈ Ρ‚.ΠΏ. НадСТно, Π½ΠΎ Π½Π΅ ΡƒΠ½ΠΈΠ²Π΅Ρ€ΡΠ°Π»ΡŒΠ½ΠΎ.

ΠžΡΠ½ΠΎΠ²Π½Ρ‹Π΅ дСсктопныС accessibility Ρ‚Π΅Ρ…Π½ΠΎΠ»ΠΎΠ³ΠΈΠΈ

Π‘Ρ‚Π°Ρ€Ρ‹ΠΉ Π΄ΠΎΠ±Ρ€Ρ‹ΠΉ Win32 API

Π‘ΠΎΠ»ΡŒΡˆΠΈΠ½ΡΡ‚Π²ΠΎ Windows ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ, написанных Π΄ΠΎ Π²Ρ‹Ρ…ΠΎΠ΄Π° WPF ΠΈ Π·Π°Ρ‚Π΅ΠΌ Windows Store, построСны Ρ‚Π°ΠΊ ΠΈΠ»ΠΈ ΠΈΠ½Π°Ρ‡Π΅ Π½Π° Win32 API. А ΠΈΠΌΠ΅Π½Π½ΠΎ, MFC, WTL, C++ Builder, Delphi, VB6 β€” всС эти инструмСнты ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ Win32 API. Π”Π°ΠΆΠ΅ Windows Forms β€” Π² Π·Π½Π°Ρ‡ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΠΉ стСпСни Win32 API совмСстимыС.

Π˜Π½ΡΡ‚Ρ€ΡƒΠΌΠ΅Π½Ρ‚Ρ‹: AutoIt (ΠΏΠΎΡ…ΠΎΠΆ Π½Π° VB) ΠΈ Python ΠΎΠ±Π΅Ρ€Ρ‚ΠΊΠ° pyautoit, AutoHotkey (собствСнный язык, Π΅ΡΡ‚ΡŒ IDispatch COM интСрфСйс), pywinauto (Python), RAutomation (Ruby), win32-autogui (Ruby).

Microsoft UI Automation

Π“Π»Π°Π²Π½Ρ‹ΠΉ плюс: тСхнология MS UI Automation ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Π΅Ρ‚ ΠΏΠΎΠ΄Π°Π²Π»ΡΡŽΡ‰Π΅Π΅ Π±ΠΎΠ»ΡŒΡˆΠΈΠ½ΡΡ‚Π²ΠΎ GUI ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ Π½Π° Windows Π·Π° Ρ€Π΅Π΄ΠΊΠΈΠΌΠΈ ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡΠΌΠΈ. ΠŸΡ€ΠΎΠ±Π»Π΅ΠΌΠ°: ΠΎΠ½Π° Π½Π΅ сильно Π»Π΅Π³Ρ‡Π΅ Π² ΠΈΠ·ΡƒΡ‡Π΅Π½ΠΈΠΈ, Ρ‡Π΅ΠΌ Win32 API. Π˜Π½Π°Ρ‡Π΅ Π½ΠΈΠΊΡ‚ΠΎ Π±Ρ‹ Π½Π΅ Π΄Π΅Π»Π°Π» ΠΎΠ±Π΅Ρ€Ρ‚ΠΎΠΊ Π½Π°Π΄ Π½Π΅ΠΉ.

ЀактичСски это Π½Π°Π±ΠΎΡ€ custom COM интСрфСйсов (Π² основном, UIAutomationCore.dll), Π° Ρ‚Π°ΠΊΠΆΠ΅ ΠΈΠΌΠ΅Π΅Ρ‚ .NET ΠΎΠ±ΠΎΠ»ΠΎΡ‡ΠΊΡƒ Π² Π²ΠΈΠ΄Π΅ namespace System.Windows.Automation. Она, кстати, ΠΈΠΌΠ΅Π΅Ρ‚ привнСсСнный Π±Π°Π³, ΠΈΠ·-Π·Π° ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ³ΠΎ Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ UI элСмСнты ΠΌΠΎΠ³ΡƒΡ‚ Π±Ρ‹Ρ‚ΡŒ ΠΏΡ€ΠΎΠΏΡƒΡ‰Π΅Π½Ρ‹. ΠŸΠΎΡΡ‚ΠΎΠΌΡƒ Π»ΡƒΡ‡ΡˆΠ΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ UIAutomationCore.dll Π½Π°ΠΏΡ€ΡΠΌΡƒΡŽ (Ссли ΡΠ»Ρ‹ΡˆΠ°Π»ΠΈ ΠΏΡ€ΠΎ UiaComWrapper Π½Π° C#, Ρ‚ΠΎ это ΠΎΠ½ΠΎ).

Разновидности COM интСрфСйсов:

(1) Π‘Π°Π·ΠΎΠ²Ρ‹ΠΉ IUknown β€” «the root of all evil». Π‘Π°ΠΌΡ‹ΠΉ Π½ΠΈΠ·ΠΊΠΎΡƒΡ€ΠΎΠ²Π½Π΅Π²Ρ‹ΠΉ, Π½ΠΈ Ρ€Π°Π·Ρƒ Π½Π΅ user-friendly.
(2) IDispatch ΠΈ ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄Π½Ρ‹Π΅ (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, Excel.Application), ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΌΠΎΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π² Python с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ ΠΏΠ°ΠΊΠ΅Ρ‚Π° win32com.client (Π²Ρ…ΠΎΠ΄ΠΈΡ‚ Π² pyWin32). Π‘Π°ΠΌΡ‹ΠΉ ΡƒΠ΄ΠΎΠ±Π½Ρ‹ΠΉ ΠΈ красивый Π²Π°Ρ€ΠΈΠ°Π½Ρ‚.
(3) Custom интСрфСйсы, с ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΌΠΈ ΡƒΠΌΠ΅Π΅Ρ‚ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ сторонний Python ΠΏΠ°ΠΊΠ΅Ρ‚ comtypes.

Π˜Π½ΡΡ‚Ρ€ΡƒΠΌΠ΅Π½Ρ‚Ρ‹: TestStack.White Π½Π° C#, pywinauto 0.6.0+, Winium.Desktop Π½Π° C#, Python-UIAutomation-for-Windows (Ρƒ Π½ΠΈΡ… исходный ΠΊΠΎΠ΄ ΡΠΈΡˆΠ½Ρ‹Ρ… ΠΎΠ±Π΅Ρ€Ρ‚ΠΎΠΊ Π½Π°Π΄ UIAutomationCore.dll Π½Π΅ раскрыт), RAutomation Π½Π° Ruby.

AT-SPI

НСсмотря Π½Π° Ρ‚ΠΎ, Ρ‡Ρ‚ΠΎ ΠΏΠΎΡ‡Ρ‚ΠΈ всС оси сСмСйства Linux построСны Π½Π° X Window System (Π² Fedora 25 «ΠΈΠΊΡΡ‹» помСняли Π½Π° Wayland), «ΠΈΠΊΡΡ‹» ΠΏΠΎΠ·Π²ΠΎΠ»ΡΡŽΡ‚ ΠΎΠΏΠ΅Ρ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΎΠΊΠ½Π°ΠΌΠΈ Π²Π΅Ρ€Ρ…Π½Π΅Π³ΠΎ уровня ΠΈ ΠΌΡ‹ΡˆΡŒΡŽ/ΠΊΠ»Π°Π²ΠΈΠ°Ρ‚ΡƒΡ€ΠΎΠΉ. Для Π΄Π΅Ρ‚Π°Π»ΡŒΠ½ΠΎΠ³ΠΎ Ρ€Π°Π·Π±ΠΎΡ€Π° ΠΏΠΎ ΠΊΠ½ΠΎΠΏΠΊΠ°ΠΌ, лист боксам ΠΈ Ρ‚Π°ΠΊ Π΄Π°Π»Π΅Π΅ β€” сущСствуСт тСхнология AT-SPI. Π£ самых популярных ΠΎΠΊΠΎΠ½Π½Ρ‹Ρ… ΠΌΠ΅Π½Π΅Π΄ΠΆΠ΅Ρ€ΠΎΠ² Π΅ΡΡ‚ΡŒ Ρ‚Π°ΠΊ Π½Π°Π·Ρ‹Π²Π°Π΅ΠΌΡ‹ΠΉ AT-SPI registry Π΄Π΅ΠΌΠΎΠ½, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΈ обСспСчиваСт для ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ Π°Π²Ρ‚ΠΎΠΌΠ°Ρ‚ΠΈΠ·ΠΈΡ€ΡƒΠ΅ΠΌΡ‹ΠΉ GUI (ΠΊΠ°ΠΊ ΠΌΠΈΠ½ΠΈΠΌΡƒΠΌ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°ΡŽΡ‚ΡΡ Qt ΠΈ GTK).

Π˜Π½ΡΡ‚Ρ€ΡƒΠΌΠ΅Π½Ρ‚Ρ‹: pyatspi2.

pyatspi2, Π½Π° ΠΌΠΎΠΉ взгляд, содСрТит слишком ΠΌΠ½ΠΎΠ³ΠΎ зависимостСй Ρ‚ΠΈΠΏΠ° Ρ‚ΠΎΠ³ΠΎ ΠΆΠ΅ PyGObject. Π‘Π°ΠΌΠ° тСхнология доступна Π² Π²ΠΈΠ΄Π΅ ΠΎΠ±Ρ‹Ρ‡Π½ΠΎΠΉ динамичСской Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ libatspi.so. К Π½Π΅ΠΉ имССтся Reference Manual. Для Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ pywinauto ΠΏΠ»Π°Π½ΠΈΡ€ΡƒΠ΅ΠΌ Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΡƒ AT-SPI ΠΈΠΌΠ΅Π΅Π½ΠΎ Ρ‚Π°ΠΊ: Ρ‡Π΅Ρ€Π΅Π· Π·Π°Π³Ρ€ΡƒΠ·ΠΊΡƒ libatspi.so ΠΈ ΠΌΠΎΠ΄ΡƒΠ»ΡŒ ctypes. Π•ΡΡ‚ΡŒ нСбольшая ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠ° Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π² использовании Π½ΡƒΠΆΠ½ΠΎΠΉ вСрсии, вСдь для GTK+ ΠΈ Qt ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ ΠΎΠ½ΠΈ Π½Π΅ΠΌΠ½ΠΎΠ³ΠΎ Ρ€Π°Π·Π½Ρ‹Π΅. ВСроятный выпуск pywinauto 0.7.0 с ΠΏΠΎΠ»Π½ΠΎΡ†Π΅Π½Π½ΠΎΠΉ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠΎΠΉ Linux ΠΌΠΎΠΆΠ½ΠΎ ΠΎΠΆΠΈΠ΄Π°Ρ‚ΡŒ Π² ΠΏΠ΅Ρ€Π²ΠΎΠΉ ΠΏΠΎΠ»ΠΎΠ²ΠΈΠ½Π΅ 2018-Π³ΠΎ.

Apple Accessibility API

На MacOS Π΅ΡΡ‚ΡŒ собствСнный язык Π°Π²Ρ‚ΠΎΠΌΠ°Ρ‚ΠΈΠ·Π°Ρ†ΠΈΠΈ AppleScript. Для Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ Ρ‡Π΅Π³ΠΎ-Ρ‚ΠΎ ΠΏΠΎΠ΄ΠΎΠ±Π½ΠΎΠ³ΠΎ Π½Π° Python, разумССтся, Π½ΡƒΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ ΠΈΠ· ObjectiveC. Начиная, каТСтся, Π΅Ρ‰Π΅ с MacOS 10.6 Π² прСдустановлСнный ΠΏΠΈΡ‚ΠΎΠ½ Π²ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ΡΡ ΠΏΠ°ΠΊΠ΅Ρ‚ pyobjc. Π­Ρ‚ΠΎ Ρ‚Π°ΠΊΠΆΠ΅ ΠΎΠ±Π»Π΅Π³Ρ‡ΠΈΡ‚ список зависимостСй для Π±ΡƒΠ΄ΡƒΡ‰Π΅ΠΉ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠΈ Π² pywinauto.

Π˜Π½ΡΡ‚Ρ€ΡƒΠΌΠ΅Π½Ρ‚Ρ‹: ΠšΡ€ΠΎΠΌΠ΅ языка Apple Script, стоит ΠΎΠ±Ρ€Π°Ρ‚ΠΈΡ‚ΡŒ Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅ Π½Π° ATOMac, ΠΎΠ½ ΠΆΠ΅ pyatom. Он совмСстим ΠΏΠΎ интСрфСйсу с LDTP, Π½ΠΎ Ρ‚Π°ΠΊΠΆΠ΅ являСтся ΡΠ°ΠΌΠΎΡΡ‚ΠΎΡΡ‚Π΅Π»ΡŒΠ½ΠΎΠΉ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΎΠΉ. На Π½Π΅ΠΌ Π΅ΡΡ‚ΡŒ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ Π°Π²Ρ‚ΠΎΠΌΠ°Ρ‚ΠΈΠ·Π°Ρ†ΠΈΠΈ iTunes Π½Π° macOs, написанный ΠΌΠΎΠΈΠΌ студСнтом. Π•ΡΡ‚ΡŒ извСстная ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠ°: Π½Π΅ Ρ€Π°Π±ΠΎΡ‚Π°ΡŽΡ‚ Π³ΠΈΠ±ΠΊΠΈΠ΅ Ρ‚Π°ΠΉΠΌΠΈΠ½Π³ΠΈ (ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹ waitFor*). Но, Π² Ρ†Π΅Π»ΠΎΠΌ, нСплохая Π²Π΅Ρ‰ΡŒ.

Как Π½Π°Ρ‡Π°Ρ‚ΡŒ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ с pywinauto

ΠŸΠ΅Ρ€Π²Ρ‹ΠΌ Π΄Π΅Π»ΠΎΠΌ стоит Π²ΠΎΠΎΡ€ΡƒΠΆΠΈΡ‚ΡŒΡΡ инспСктором GUI ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² (Ρ‚ΠΎ, Ρ‡Ρ‚ΠΎ Π½Π°Π·Ρ‹Π²Π°ΡŽΡ‚ Spy tool). Он ΠΏΠΎΠΌΠΎΠΆΠ΅Ρ‚ ΠΈΠ·ΡƒΡ‡ΠΈΡ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΈΠ·Π½ΡƒΡ‚Ρ€ΠΈ: ΠΊΠ°ΠΊ устроСна иСрархия элСмСнтов, ΠΊΠ°ΠΊΠΈΠ΅ свойства доступны. Π‘Π°ΠΌΡ‹Π΅ извСстныС инспСкторы ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ²:

  • Spy++ β€” Π²Ρ…ΠΎΠ΄ΠΈΡ‚ Π² поставку Visual Studio, Π²ΠΊΠ»ΡŽΡ‡Π°Ρ Express ΠΈΠ»ΠΈ Community Edition. Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ Win32 API. Π’Π°ΠΊΠΆΠ΅ извСстСн Π΅Π³ΠΎ ΠΊΠ»ΠΎΠ½ AutoIt Window Info.
  • Inspect.exe β€” Π²Ρ…ΠΎΠ΄ΠΈΡ‚ Π² Windows SDK. Если ΠΎΠ½ Ρƒ вас установлСн, Ρ‚ΠΎ Π½Π° 64-Π±ΠΈΡ‚Π½ΠΎΠΉ Windows ΠΌΠΎΠΆΠ½ΠΎ Π½Π°ΠΉΡ‚ΠΈ Π΅Π³ΠΎ Π² ΠΏΠ°ΠΏΠΊΠ΅ C:Program Files (x86)Windows Kits<winver>binx64. Π’ самом инспСкторС Π½ΡƒΠΆΠ½ΠΎ Π²Ρ‹Π±Ρ€Π°Ρ‚ΡŒ Ρ€Π΅ΠΆΠΈΠΌ UI Automation вмСсто MS AA (Active Accessibility, ΠΏΡ€Π΅Π΄ΠΎΠΊ UI Automation).

ΠŸΡ€ΠΎΡΠ²Π΅Ρ‚ΠΈΠ² ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ насквозь, Π²Ρ‹Π±ΠΈΡ€Π°Π΅ΠΌ бэкСнд, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π±ΡƒΠ΄Π΅ΠΌ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ. Достаточно ΡƒΠΊΠ°Π·Π°Ρ‚ΡŒ имя бэкСнда ΠΏΡ€ΠΈ создании ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π° Application.

  • backend=»win32″ β€” ΠΏΠΎΠΊΠ° ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ, Ρ…ΠΎΡ€ΠΎΡˆΠΎ Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ с MFC, WTL, VB6 ΠΈ Π΄Ρ€ΡƒΠ³ΠΈΠΌΠΈ legacy прилоТСниями.
  • backend=»uia» β€” Π½ΠΎΠ²Ρ‹ΠΉ бэкСнд для MS UI Automation: идСально Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ с WPF ΠΈ WinForms; Ρ‚Π°ΠΊΠΆΠ΅ Ρ…ΠΎΡ€ΠΎΡˆ для Delphi ΠΈ Windows Store ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ; Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ с Qt5 ΠΈ Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΌΠΈ Java прилоТСниями. И Π²ΠΎΠΎΠ±Ρ‰Π΅, Ссли Inspect.exe Π²ΠΈΠ΄ΠΈΡ‚ элСмСнты ΠΈ ΠΈΡ… свойства, Π·Π½Π°Ρ‡ΠΈΡ‚ этот бэкСнд ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ΠΈΡ‚. Π’ ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΠ΅, Π±ΠΎΠ»ΡŒΡˆΠΈΠ½ΡΡ‚Π²ΠΎ Π±Ρ€Π°ΡƒΠ·Π΅Ρ€ΠΎΠ² Ρ‚ΠΎΠΆΠ΅ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Π΅Ρ‚ UI Automation (Mozilla ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ, Π° Π₯Ρ€ΠΎΠΌΡƒ ΠΏΡ€ΠΈ запускС Π½ΡƒΠΆΠ½ΠΎ ΡΠΊΠΎΡ€ΠΌΠΈΡ‚ΡŒ ΠΊΠ»ΡŽΡ‡ ΠΊΠΎΠΌΠ°Π½Π΄Π½ΠΎΠΉ строки --force-renderer-accessibility, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΡƒΠ²ΠΈΠ΄Π΅Ρ‚ΡŒ элСмСнты Π½Π° страницах Π² Inspect.exe). ΠšΠΎΠ½Π΅Ρ‡Π½ΠΎ, конкурСнция с Selenium Π² этой области навряд Π»ΠΈ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½Π°. ΠŸΡ€ΠΎΡΡ‚ΠΎ Π΅Ρ‰Π΅ ΠΎΠ΄ΠΈΠ½ способ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ с Π±Ρ€Π°ΡƒΠ·Π΅Ρ€ΠΎΠΌ (ΠΌΠΎΠΆΠ΅Ρ‚ ΠΏΡ€ΠΈΠ³ΠΎΠ΄ΠΈΡ‚ΡŒΡΡ для кросс-ΠΏΡ€ΠΎΠ΄ΡƒΠΊΡ‚ΠΎΠ²ΠΎΠ³ΠΎ сцСнария).

Π’Ρ…ΠΎΠ΄Π½Ρ‹Π΅ Ρ‚ΠΎΡ‡ΠΊΠΈ для Π°Π²Ρ‚ΠΎΠΌΠ°Ρ‚ΠΈΠ·Π°Ρ†ΠΈΠΈ

ΠŸΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ достаточно ΠΈΠ·ΡƒΡ‡Π΅Π½ΠΎ. ΠŸΠΎΡ€Π° ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ Application ΠΈ Π·Π°ΠΏΡƒΡΡ‚ΠΈΡ‚ΡŒ Π΅Π³ΠΎ ΠΈΠ»ΠΈ ΠΏΡ€ΠΈΡΠΎΠ΅Π΄ΠΈΠ½ΠΈΡ‚ΡŒΡΡ ΠΊ ΡƒΠΆΠ΅ Π·Π°ΠΏΡƒΡ‰Π΅Π½Π½ΠΎΠΌΡƒ. Π­Ρ‚ΠΎ Π½Π΅ просто ΠΊΠ»ΠΎΠ½ стандартного класса 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. Π’Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΎΠΏΠΈΡΠ°Ρ‚ΡŒ ΠΎΠΊΠ½ΠΎ/элСмСнт ΠΏΡ€ΠΈΠ±Π»ΠΈΠΆΠ΅Π½Π½ΠΎ ΠΈΠ»ΠΈ Π±ΠΎΠ»Π΅Π΅ Π΄Π΅Ρ‚Π°Π»ΡŒΠ½ΠΎ, Π΄Π°ΠΆΠ΅ Ссли ΠΎΠ½ΠΎ Π΅Ρ‰Π΅ Π½Π΅ сущСствуСт ΠΈΠ»ΠΈ ΡƒΠΆΠ΅ Π·Π°ΠΊΡ€Ρ‹Ρ‚ΠΎ. БпСцификация ΠΎΠΊΠ½Π° (ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ WindowSpecification) Ρ…Ρ€Π°Π½ΠΈΡ‚ Π² сСбС ΠΊΡ€ΠΈΡ‚Π΅Ρ€ΠΈΠΈ, ΠΏΠΎ ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΌ Π½ΡƒΠΆΠ½ΠΎ ΠΈΡΠΊΠ°Ρ‚ΡŒ Ρ€Π΅Π°Π»ΡŒΠ½ΠΎΠ΅ ΠΎΠΊΠ½ΠΎ ΠΈΠ»ΠΈ элСмСнт.

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ Π΄Π΅Ρ‚Π°Π»ΡŒΠ½ΠΎΠΉ спСцификации ΠΎΠΊΠ½Π°:

>>> 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(), Ρ‚Π°ΠΊ Ρ‡Ρ‚ΠΎ Ρ„ΠΈΠ½Π°Π»ΡŒΠ½Ρ‹ΠΉ ΠΊΠΎΠ΄ становится ΠΊΠΎΡ€ΠΎΡ‡Π΅. Π Π΅ΠΊΠΎΠΌΠ΅Π½Π΄ΡƒΠ΅ΠΌ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π΅Π³ΠΎ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ для ΠΎΡ‚Π»Π°Π΄ΠΊΠΈ. Π‘Π»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠ΅ Π΄Π²Π΅ строки Π΄Π΅Π»Π°ΡŽΡ‚ Π°Π±ΡΠΎΠ»ΡŽΡ‚Π½ΠΎ ΠΎΠ΄Π½ΠΎ ΠΈ Ρ‚ΠΎ ΠΆΠ΅:

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 ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ Ρ‚Π°ΠΊ Π½Π°Π·Ρ‹Π²Π°Π΅ΠΌΡ‹ΠΉ «best match» Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΠΌ поиска, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ устойчив ΠΊ ΠΎΠΏΠ΅Ρ‡Π°Ρ‚ΠΊΠ°ΠΌ ΠΈ нСбольшим вариациям.

app.UntitledNotepad
# Ρ‚ΠΎ ΠΆΠ΅ самоС, Ρ‡Ρ‚ΠΎ
app.window(best_match='UntitledNotepad')

Если всС-Ρ‚Π°ΠΊΠΈ Π½ΡƒΠΆΠ½Ρ‹ Unicode строки (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, для русского языка), ΠΏΡ€ΠΎΠ±Π΅Π»Ρ‹ ΠΈ Ρ‚.ΠΏ., ΠΌΠΎΠΆΠ½ΠΎ Π΄Π΅Π»Π°Ρ‚ΡŒ доступ ΠΏΠΎ ΠΊΠ»ΡŽΡ‡Ρƒ (ΠΊΠ°ΠΊ Π±ΡƒΠ΄Ρ‚ΠΎ это ΠΎΠ±Ρ‹Ρ‡Π½Ρ‹ΠΉ ΡΠ»ΠΎΠ²Π°Ρ€ΡŒ):

app['Untitled - Notepad']
# Ρ‚ΠΎ ΠΆΠ΅ самоС, Ρ‡Ρ‚ΠΎ
app.window(best_match='Untitled - Notepad')

ΠŸΡΡ‚ΡŒ ΠΏΡ€Π°Π²ΠΈΠ» для магичСских ΠΈΠΌΠ΅Π½

Как ΡƒΠ·Π½Π°Ρ‚ΡŒ эталонныС магичСскиС ΠΈΠΌΠ΅Π½Π°? Π’Π΅, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΏΡ€ΠΈΡΠ²Π°ΠΈΠ²Π°ΡŽΡ‚ΡΡ элСмСнту ΠΏΠ΅Ρ€Π΅Π΄ поиском. Если Π²Ρ‹ ΡƒΠΊΠ°Π·Π°Π»ΠΈ имя, достаточно ΠΏΠΎΡ…ΠΎΠΆΠ΅Π΅ Π½Π° эталон, Π·Π½Π°Ρ‡ΠΈΡ‚ элСмСнт Π±ΡƒΠ΄Π΅Ρ‚ Π½Π°ΠΉΠ΄Π΅Π½.

  1. По Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΊΡƒ (тСкст, имя): app.Properties.OK.click()
  2. По тСксту ΠΈ ΠΏΠΎ Ρ‚ΠΈΠΏΡƒ элСмСнта: app.Properties.OKButton.click()
  3. По Ρ‚ΠΈΠΏΡƒ ΠΈ ΠΏΠΎ Π½ΠΎΠΌΠ΅Ρ€Ρƒ: app.Properties.Button3.click() (ΠΈΠΌΠ΅Π½Π° Button0 ΠΈ Button1 привязаны ΠΊ ΠΏΠ΅Ρ€Π²ΠΎΠΌΡƒ Π½Π°ΠΉΠ΄Π΅Π½Π½ΠΎΠΌΡƒ элСмСнту, Button2 β€” ΠΊΠΎ Π²Ρ‚ΠΎΡ€ΠΎΠΌΡƒ, ΠΈ дальшС ΡƒΠΆΠ΅ ΠΏΠΎ порядку β€” Ρ‚Π°ΠΊ историчСски слоТилось)
  4. По статичСскому тСксту (слСва ΠΈΠ»ΠΈ свСрху) ΠΈ ΠΏΠΎ Ρ‚ΠΈΠΏΡƒ: app.OpenDialog.FileNameEdit.set_text("") (ΠΏΠΎΠ»Π΅Π·Π½ΠΎ для элСмСнтов с динамичСским тСкстом)
  5. По Ρ‚ΠΈΠΏΡƒ ΠΈ ΠΏΠΎ тСксту Π²Π½ΡƒΡ‚Ρ€ΠΈ: app.Properties.TabControlSharing.select("General")

ΠžΠ±Ρ‹Ρ‡Π½ΠΎ Π΄Π²Π°-Ρ‚Ρ€ΠΈ ΠΏΡ€Π°Π²ΠΈΠ»Π° ΠΏΡ€ΠΈΠΌΠ΅Π½ΡΡŽΡ‚ΡΡ ΠΎΠ΄Π½ΠΎΠ²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎ, Ρ€Π΅Π΄ΠΊΠΎ большС. Π§Ρ‚ΠΎΠ±Ρ‹ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΈΡ‚ΡŒ, ΠΊΠ°ΠΊΠΈΠ΅ ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½ΠΎ ΠΈΠΌΠ΅Π½Π° доступны для ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ элСмСнта, ΠΌΠΎΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΌΠ΅Ρ‚ΠΎΠ΄ print_control_identifiers(). Он ΠΌΠΎΠΆΠ΅Ρ‚ ΠΏΠ΅Ρ‡Π°Ρ‚Π°Ρ‚ΡŒ Π΄Π΅Ρ€Π΅Π²ΠΎ элСмСнтов ΠΊΠ°ΠΊ Π½Π° экран, Ρ‚Π°ΠΊ ΠΈ Π² Ρ„Π°ΠΉΠ». Для ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ элСмСнта ΠΏΠ΅Ρ‡Π°Ρ‚Π°ΡŽΡ‚ΡΡ Π΅Π³ΠΎ эталонныС магичСскиС ΠΈΠΌΠ΅Π½Π°. Π’Π°ΠΊΠΆΠ΅ ΠΌΠΎΠΆΠ½ΠΎ ΡΠΊΠΎΠΏΠΈΠΏΠ°ΡΡ‚ΠΈΡ‚ΡŒ ΠΎΡ‚Ρ‚ΡƒΠ΄Π° Π±ΠΎΠ»Π΅Π΅ Π΄Π΅Ρ‚Π°Π»ΡŒΠ½Ρ‹Π΅ спСцификации Π΄ΠΎΡ‡Π΅Ρ€Π½ΠΈΡ… элСмСнтов. Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ Π² скриптС Π±ΡƒΠ΄Π΅Ρ‚ Π²Ρ‹Π³Π»ΡΠ΄Π΅Ρ‚ΡŒ Ρ‚Π°ΠΊ:

app.Properties.child_window(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(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(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(title="Type:", auto_id="13080", control_type="Text")
   |
   | Edit - 'Type:'    (L790, T643, R1036, B666)
   | [u'4', 'Edit2', u'Type:Edit']
   | child_window(title="Type:", auto_id="13059", control_type="Edit")
   |
   | Static - 'Location:'    (L717, T669, R780, B684)
   | [u'Location:Static', u'Location:', u'Static2']
   | child_window(title="Location:", auto_id="13089", control_type="Text")
   |
   | Edit - 'Location:'    (L790, T669, R1036, B692)
   | ['Edit3', u'Location:Edit', u'5']
   | child_window(title="Location:", auto_id="13065", control_type="Edit")
   |
   | Static - 'Size:'    (L717, T695, R780, B710)
   | [u'Size:Static', u'Size:', u'Static3']
   | child_window(title="Size:", auto_id="13081", control_type="Text")
   |
   | Edit - 'Size:'    (L790, T695, R1036, B718)
   | ['Edit4', u'6', u'Size:Edit']
   | child_window(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(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(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(title="Contains:", auto_id="13088", control_type="Text")
   |
   | Edit - 'Contains:'    (L790, T747, R1036, B770)
   | [u'8', 'Edit6', u'Contains:Edit']
   | child_window(title="Contains:", auto_id="13087", control_type="Edit")
   |
   | Image - 'Contains:'    (L717, T773, R1035, B775)
   | [u'Contains:Image', 'Image3', u'Contains:2']
   | child_window(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(title="Created:", auto_id="13092", control_type="Text")
   |
   | Edit - 'Created:'    (L790, T786, R1036, B809)
   | [u'Created:Edit', 'Edit7', u'9']
   | child_window(title="Created:", auto_id="13072", control_type="Edit")
   |
   | Image - 'Created:'    (L717, T812, R1035, B814)
   | [u'Created:Image', 'Image4', u'Created:2']
   | child_window(title="Created:", auto_id="13097", control_type="Image")
   |
   | Static - 'Attributes:'    (L717, T825, R780, B840)
   | [u'Attributes:Static', u'Static7', u'Attributes:']
   | child_window(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(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(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(title="Advanced...", auto_id="13154", control_type="Button")
   |
   | Button - 'OK'    (L814, T968, R889, B991)
   | ['Button2', u'OK', u'OKButton']
   | child_window(title="OK", auto_id="1", control_type="Button")
   |
   | Button - 'Cancel'    (L895, T968, R970, B991)
   | ['Button3', u'CancelButton', u'Cancel']
   | child_window(title="Cancel", auto_id="2", control_type="Button")
   |
   | Button - 'Apply'    (L976, T968, R1051, B991)
   | ['Button4', u'ApplyButton', u'Apply']
   | child_window(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(title="General", control_type="TabItem")
   |    |
   |    | TabItem - 'Sharing'    (L753, T558, R801, B576)
   |    | [u'Sharing', u'SharingTabItem', 'TabItem2']
   |    | child_window(title="Sharing", control_type="TabItem")
   |    |
   |    | TabItem - 'Security'    (L801, T558, R851, B576)
   |    | [u'Security', 'TabItem3', u'SecurityTabItem']
   |    | child_window(title="Security", control_type="TabItem")
   |    |
   |    | TabItem - 'Previous Versions'    (L851, T558, R947, B576)
   |    | [u'Previous VersionsTabItem', u'Previous Versions', 'TabItem4']
   |    | child_window(title="Previous Versions", control_type="TabItem")
   |    |
   |    | TabItem - 'Customize'    (L947, T558, R1007, B576)
   |    | [u'CustomizeTabItem', 'TabItem5', u'Customize']
   |    | child_window(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(title="System", auto_id="MenuBar", control_type="MenuBar")
   |    |    |
   |    |    | MenuItem - 'System'    (L696, T526, R718, B548)
   |    |    | [u'System2', u'MenuItem', u'SystemMenuItem']
   |    |    | child_window(title="System", control_type="MenuItem")
   |    |
   |    | Button - 'Close'    (L1024, T519, R1058, B549)
   |    | [u'CloseButton', u'Close', 'Button5']
   |    | child_window(title="Close", control_type="Button")

Π’ Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Ρ… случаях ΠΏΠ΅Ρ‡Π°Ρ‚ΡŒ всСго Π΄Π΅Ρ€Π΅Π²Π° ΠΌΠΎΠΆΠ΅Ρ‚ Ρ‚ΠΎΡ€ΠΌΠΎΠ·ΠΈΡ‚ΡŒ (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, Π² iTunes Π½Π° ΠΎΠ΄Π½ΠΎΠΉ Π²ΠΊΠ»Π°Π΄ΠΊΠ΅ Π°ΠΆ Ρ‚Ρ€ΠΈ тысячи элСмСнтов!), Π½ΠΎ ΠΌΠΎΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ depth (Π³Π»ΡƒΠ±ΠΈΠ½Π°): depth=1 β€” сам элСмСнт, depth=2 β€” Ρ‚ΠΎΠ»ΡŒΠΊΠΎ нСпосрСдствСнныС Π΄Π΅Ρ‚ΠΈ, ΠΈ Ρ‚Π°ΠΊ Π΄Π°Π»Π΅Π΅. Π•Π³ΠΎ ΠΆΠ΅ ΠΌΠΎΠΆΠ½ΠΎ ΡƒΠΊΠ°Π·Ρ‹Π²Π°Ρ‚ΡŒ Π² спСцификациях ΠΏΡ€ΠΈ создании child_window.

ΠŸΡ€ΠΈΠΌΠ΅Ρ€Ρ‹

ΠœΡ‹ постоянно пополняСм список ΠΏΡ€ΠΈΠΌΠ΅Ρ€ΠΎΠ² Π² Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΈ. Из свСТих стоит ΠΎΡ‚ΠΌΠ΅Ρ‚ΠΈΡ‚ΡŒ Π°Π²Ρ‚ΠΎΠΌΠ°Ρ‚ΠΈΠ·Π°Ρ†ΠΈΡŽ сСтСвого Π°Π½Π°Π»ΠΈΠ·Π°Ρ‚ΠΎΡ€Π° WireShark (это Ρ…ΠΎΡ€ΠΎΡˆΠΈΠΉ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ Qt5 прилоТСния; хотя эту Π·Π°Π΄Π°Ρ‡Ρƒ ΠΌΠΎΠΆΠ½ΠΎ Ρ€Π΅ΡˆΠ°Ρ‚ΡŒ ΠΈ Π±Π΅Π· GUI, вСдь Π΅ΡΡ‚ΡŒ scapy.Sniffer ΠΈΠ· питоновского ΠΏΠ°ΠΊΠ΅Ρ‚Π° scapy). Π’Π°ΠΊΠΆΠ΅ Π΅ΡΡ‚ΡŒ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ Π°Π²Ρ‚ΠΎΠΌΠ°Ρ‚ΠΈΠ·Π°Ρ†ΠΈΠΈ MS Paint с Π΅Π³ΠΎ Ribbon Ρ‚ΡƒΠ»Π±Π°Ρ€ΠΎΠΌ.

Π•Ρ‰Π΅ ΠΎΠ΄ΠΈΠ½ ΠΎΡ‚Π»ΠΈΡ‡Π½Ρ‹ΠΉ ΠΏΡ€ΠΈΠΌΠ΅Ρ€, написанный ΠΌΠΎΠΈΠΌ студСнтом: пСрСтаскиваниС Ρ„Π°ΠΉΠ»Π° ΠΈΠ· explorer.exe Π½Π° Chrome страницу для Google Drive (ΠΎΠ½ ΠΏΠ΅Ρ€Π΅ΠΊΠΎΡ‡ΡƒΠ΅Ρ‚ Π² Π³Π»Π°Π²Π½Ρ‹ΠΉ Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΉ Ρ‡ΡƒΡ‚ΡŒ ΠΏΠΎΠ·ΠΆΠ΅).

И, ΠΊΠΎΠ½Π΅Ρ‡Π½ΠΎ, ΠΏΡ€ΠΈΠΌΠ΅Ρ€ подписки Π½Π° события ΠΊΠ»Π°Π²ΠΈΠ°Ρ‚ΡƒΡ€Ρ‹ (hot keys) ΠΈ ΠΌΡ‹ΡˆΠΈ:
hook_and_listen.py.

Благодарности

ΠžΡ‚Π΄Π΅Π»ΡŒΠ½ΠΎΠ΅ спасибо β€” Ρ‚Π΅ΠΌ, ΠΊΡ‚ΠΎ постоянно ΠΏΠΎΠΌΠΎΠ³Π°Π΅Ρ‚ Ρ€Π°Π·Π²ΠΈΠ²Π°Ρ‚ΡŒ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚. Для мСня ΠΈ Π’Π°Π»Π΅Π½Ρ‚ΠΈΠ½Π° это постоянноС Ρ…ΠΎΠ±Π±ΠΈ. Π”Π²ΠΎΠ΅ ΠΌΠΎΠΈΡ… студСнтов ΠΈΠ· ННГУ Π½Π΅Π΄Π°Π²Π½ΠΎ Π·Π°Ρ‰ΠΈΡ‚ΠΈΠ»ΠΈ Π΄ΠΈΠΏΠ»ΠΎΠΌΡ‹ Π±Π°ΠΊΠ°Π»Π°Π²Ρ€Π° ΠΏΠΎ этой Ρ‚Π΅ΠΌΠ΅. АлСксандр внСс большой Π²ΠΊΠ»Π°Π΄ Π² ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΡƒ MS UI Automation ΠΈ Π½Π΅Π΄Π°Π²Π½ΠΎ Π½Π°Ρ‡Π°Π» Π΄Π΅Π»Π°Ρ‚ΡŒ автоматичСский Π³Π΅Π½Π΅Ρ€Π°Ρ‚ΠΎΡ€ ΠΊΠΎΠ΄Π° ΠΏΠΎ ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΡƒ «Π·Π°ΠΏΠΈΡΡŒ-воспроизвСдСниС» Π½Π° основС тСкстовых свойств (это самая слоТная Ρ„ΠΈΡ‡Π°), ΠΏΠΎΠΊΠ° Ρ‚ΠΎΠ»ΡŒΠΊΠΎ для «uia» бэкСнда. Иван Ρ€Π°Π·Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Π΅Ρ‚ Π½ΠΎΠ²Ρ‹ΠΉ бэкСнд ΠΏΠΎΠ΄ Linux Π½Π° основС AT-SPI (ΠΌΠΎΠ΄ΡƒΠ»ΠΈ mouse ΠΈ keyboard Π½Π° основС python-xlib β€” ΡƒΠΆΠ΅ Π² Ρ€Π΅Π»ΠΈΠ·Π°Ρ… 0.6.x).

ΠŸΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ я довольно Π΄Π°Π²Π½ΠΎ Ρ‡ΠΈΡ‚Π°ΡŽ спСцкурс ΠΏΠΎ Π°Π²Ρ‚ΠΎΠΌΠ°Ρ‚ΠΈΠ·Π°Ρ†ΠΈΠΈ Π½Π° Python, Ρ‡Π°ΡΡ‚ΡŒ студСнтов-магистров Π²Ρ‹ΠΏΠΎΠ»Π½ΡΡŽΡ‚ домашниС задания, рСализуя нСбольшиС Ρ„ΠΈΡ‡ΠΈ ΠΈΠ»ΠΈ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Ρ‹ Π°Π²Ρ‚ΠΎΠΌΠ°Ρ‚ΠΈΠ·Π°Ρ†ΠΈΠΈ. НСкоторыС ΠΊΠ»ΡŽΡ‡Π΅Π²Ρ‹Π΅ Π²Π΅Ρ‰ΠΈ Π½Π° стадии исслСдований Ρ‚ΠΎΠΆΠ΅ ΠΊΠΎΠ³Π΄Π°-Ρ‚ΠΎ раскопали ΠΈΠΌΠ΅Π½Π½ΠΎ студСнты. Π₯отя ΠΈΠ½ΠΎΠ³Π΄Π° Π·Π° качСством ΠΊΠΎΠ΄Π° приходится строго ΡΠ»Π΅Π΄ΠΈΡ‚ΡŒ. Π’ этом сильно ΠΏΠΎΠΌΠΎΠ³Π°ΡŽΡ‚ статичСскиС Π°Π½Π°Π»ΠΈΠ·Π°Ρ‚ΠΎΡ€Ρ‹ (QuantifiedCode, Codacy ΠΈ Landscape) ΠΈ автоматичСскиС тСсты Π² ΠΎΠ±Π»Π°ΠΊΠ΅ (сСрвис AppVeyor) с ΠΏΠΎΠΊΡ€Ρ‹Ρ‚ΠΈΠ΅ΠΌ ΠΊΠΎΠ΄Π° Π² Ρ€Π°ΠΉΠΎΠ½Π΅ 95%.

Π’Π°ΠΊΠΆΠ΅ спасибо всСм, ΠΊΡ‚ΠΎ оставляСт ΠΎΡ‚Π·Ρ‹Π²Ρ‹, Π·Π°Π²ΠΎΠ΄ΠΈΡ‚ Π±Π°Π³ΠΈ ΠΈ присылаСт ΠΏΡƒΠ»Π» рСквСсты!

Π”ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹Π΅ рСсурсы

Π—Π° вопросами ΠΌΡ‹ слСдим ΠΏΠΎ Ρ‚Π΅Π³Ρƒ Π½Π° StackOverflow (Π½Π΅Π΄Π°Π²Π½ΠΎ появился Ρ‚Π΅Π³ Π² русской вСрсии SO) ΠΈ ΠΏΠΎ ΠΊΠ»ΡŽΡ‡Π΅Π²ΠΎΠΌΡƒ слову Π½Π° ВостСрС. Π•ΡΡ‚ΡŒ русскоязычный Ρ‡Π°Ρ‚ Π² Gitter’Π΅.

ΠšΠ°ΠΆΠ΄Ρ‹ΠΉ мСсяц обновляСм Ρ€Π΅ΠΉΡ‚ΠΈΠ½Π³ open-source Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊ для GUI тСстирования. По количСству Π·Π²Π΅Π·Π΄ Π½Π° Π³ΠΈΡ‚Ρ…Π°Π±Π΅ быстрСС растут Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Autohotkey (Ρƒ Π½ΠΈΡ… ΠΎΡ‡Π΅Π½ΡŒ большоС сообщСство ΠΈ длинная история) ΠΈ PyAutoGUI (Π²ΠΎ ΠΌΠ½ΠΎΠ³ΠΎΠΌ благодаря популярности ΠΊΠ½ΠΈΠ³ Π΅Π΅ Π°Π²Ρ‚ΠΎΡ€Π° Al Sweigart: «Automate the Boring Stuff with Python» ΠΈ Π΄Ρ€ΡƒΠ³ΠΈΡ…).

Π˜ΡΡ‚ΠΎΡ‡Π½ΠΈΠΊ: habr.com

Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ ΠΊΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΉ