Automatizácia GUI pracovnej plochy v Pythone + pywinauto: ako sa spriateliť s MS UI Automation

Knižnica Python pywinauto — je open source projekt na automatizáciu desktopových grafických aplikácií na WindowsZa posledné dva roky pridal významné nové funkcie:

  • Podpora pre technológiu automatizácie používateľského rozhrania MS. Rozhranie zostáva rovnaké a teraz podporuje WinForms, WPF, Qt5, Windows Obchod (UWP) a tak ďalej - takmer všetko, čo je zapnuté Windows.
  • Systém backendov/pluginov (v súčasnosti sú pod kapotou dva z nich: predvolený "win32" a nové "uia"). Potom plynulo prejdeme k multiplatformovému.
  • Win32 háčiky pre myš a klávesnicu (klávesové skratky v duchu pyHook).

Poskytneme tiež krátky prehľad toho, čo je k dispozícii v open source pre automatizáciu pracovnej plochy (bez toho, aby sme sa tvárili ako vážne porovnanie).

Tento článok je čiastočným prepisom správy z konferencie SQA Days 20 v Minsku (videokazeta и diapozitívov), čiastočne ruská verzia príručka Začíname pre pywinauto.

Začnime krátkym prehľadom open source v tejto oblasti. Pri desktopových GUI aplikáciách je všetko o niečo komplikovanejšie ako pri webe, ktorý má Selenium. Tu sú hlavné prístupy:

Súradnicová metóda

Pevne zakódujte klikacie body, dúfame v úspešné zásahy.
[+] Multiplatformový, ľahko implementovateľný.
[+] Je jednoduché „nahrať a znova prehrať“ testovacie nahrávky.
[-] Najviac nestabilné pri zmene rozlíšenia obrazovky, motívu, fontov, veľkosti okien atď.
[-] Vyžaduje sa obrovské úsilie podpory; často je jednoduchšie obnoviť testy od začiatku alebo testovať manuálne.
[-] Automatizuje iba akcie, existujú aj iné metódy overovania a získavania údajov.

Nástroje (viacplatformové): autopitva, PyAutoGUI, PyUserInput a veľa ďalších. Túto funkciu zvyčajne zahŕňajú zložitejšie nástroje (nie vždy medzi platformami).

Stojí za to povedať, že súradnicová metóda môže dopĺňať iné prístupy. Napríklad pri vlastnej grafike môžete kliknúť na relatívne súradnice (z ľavého horného rohu okna/prvku a nie z celej obrazovky) – zvyčajne je to celkom spoľahlivé, najmä ak vezmete do úvahy dĺžku/šírku celý prvok (potom neublížia rôzne rozlíšenia obrazovky).

Ďalšia možnosť: na testovanie prideľte iba jeden počítač so stabilnými nastaveniami (nie medzi platformami, ale v niektorých prípadoch je to dobré).

Rozpoznanie referenčného obrazu

[+] Viacplatformový
[+-] Relatívne spoľahlivá (lepšia ako súradnicová metóda), ale stále vyžaduje určité triky.
[-+] Relatívne pomaly, pretože Vyžaduje prostriedky CPU na rozpoznávanie algoritmov.
[-] Rozpoznávanie textu (OCR) spravidla neprichádza do úvahy => textové údaje sa nedajú získať. Pokiaľ viem, existujúce riešenia OCR nie sú pre tento typ úloh veľmi spoľahlivé a nie sú široko používané (ak to tak ešte nie je, vítam vás v komentároch).

nástroje: Sikuli, lokaj (kompatibilný so Sikuli, čistý Python), PyAutoGUI.

Technológia dostupnosti

[+] Najspoľahlivejšia metóda, pretože umožňuje vyhľadávať podľa textu bez ohľadu na to, ako ho vykresľuje systém alebo rámec.
[+] Umožňuje extrahovať textové údaje => jednoduchšie overiť výsledky testov.
[+] Spravidla najrýchlejšie, pretože nespotrebováva takmer žiadne CPU zdroje.
[-] Je ťažké vytvoriť multiplatformový nástroj: absolútne všetky open-source knižnice podporujú jednu alebo dve technológie prístupnosti. Windows/LinuxMacOS nie je plne podporovaný nikým okrem platených programov ako TestComplete, UFT alebo Squish.
[-] Takáto technológia nie je v zásade vždy dostupná. Napríklad testovanie obrazovky načítania vo VirtualBoxe - to sa nedá urobiť bez rozpoznávania obrázkov. Ale v mnohých klasických prípadoch je prístup prístupnosti stále použiteľný. O tom sa bude diskutovať ďalej.

nástroje: TestStack.White v C#, Winium.Desktop v C# (kompatibilný so selénom), Ovládač MS WinApp v C# (kompatibilné s Appium), pywinauto, pyatom (kompatibilné s LDTP) Python-UIAutomation-pre-Windows, RAutomatizácia v Ruby, LDTP (Linux Projekt testovania počítačov) a jeho Windows verzia kobra.

LDTP je snáď jediný multiplatformový open-source nástroj (presnejšie rodina knižníc) založený na technológiách dostupnosti. Nie je však veľmi populárny. Sám som ho nepoužil, ale podľa recenzií jeho rozhranie nie je najpohodlnejšie. Ak máte pozitívnu spätnú väzbu, podeľte sa o ňu v komentároch.

Testovacie zadné vrátka (aka halový bicykel)

Pre multiplatformové aplikácie si vývojári často vytvárajú interný mechanizmus na zabezpečenie testovateľnosti. V aplikácii napríklad vytvoria servisný TCP server, pripájajú sa k nemu testy a posielajú textové príkazy: na čo kliknúť, kde získať dáta atď. Spoľahlivý, ale nie univerzálny.

Základné technológie dostupnosti desktopu

Staré dobré Win32 API

Väčšina Windows aplikácie napísané pred vydaním WPF a po ňom Windows Store sú tak či onak vytvorené na rozhraní Win32 API. Konkrétne MFC, WTL, C++ Builder, Delphi, VB6 – všetky tieto nástroje používajú rozhranie Win32 API. Dokonca aj Windows Formuláre sú do značnej miery kompatibilné s rozhraním Win32 API.

nástroje: Na streche (podobne ako VB) a Python wrapper pyautoit, AutoHotkey (vlastný jazyk, existuje rozhranie COM IDispatch), pywinauto (Python) RAutomatizácia (rubín) win32-autogui (Rubín).

Microsoft UI Automation

Hlavná výhoda: Technológia automatizácie používateľského rozhrania MS podporuje prevažnú väčšinu aplikácií s grafickým rozhraním na Windows Až na zriedkavé výnimky. Problém: nie je oveľa jednoduchšie sa naučiť ho používať ako Win32 API. Inak by preň nikto nevytváral obalovacie rozhrania.

V skutočnosti ide o sadu vlastných rozhraní COM (hlavne UIAutomationCore.dll), a má vo formulári aj obal .NET namespace System.Windows.Automation. Mimochodom, má zavedenú chybu, kvôli ktorej môžu chýbať niektoré prvky používateľského rozhrania. Preto je lepšie použiť priamo UIAutomationCore.dll (ak ste počuli o UiaComWrapper v C#, potom je to ono).

Typy rozhraní COM:

(1) Základná IUznáma – „koreň všetkého zla“. Najnižšia úroveň, nikdy užívateľsky prívetivá.
(2) Idispatch a deriváty (napr Excel.Application), ktorý je možné použiť v Pythone pomocou balíka win32com.client (súčasť pyWin32). Najpohodlnejšia a najkrajšia možnosť.
(3) Vlastné rozhrania, s ktorými môže pracovať balík Python tretej strany komtypy.

nástroje: TestStack.White v C#, pywinauto 0.6.0 + Winium.Desktop v C#, Python-UIAutomation-pre-Windows (ich zdrojový kód pre C wrappery cez UIAutomationCore.dll nie je zverejnený), RAutomatizácia v Ruby.

AT-SPI

Napriek tomu, že takmer všetky sekery rodiny Linux Postavený na systéme X Window (vo Fedore 25 bol „X“ nahradený systémom Wayland), „X“ umožňuje ovládať iba okná najvyššej úrovne a myš/klávesnicu. Pre podrobnú analýzu tlačidiel, zoznamov atď. je k dispozícii technológia AT-SPI. Najpopulárnejšie správcov okien majú takzvaný démon registra AT-SPI, ktorý poskytuje automatizované grafické rozhranie pre aplikácie (podporované sú aspoň Qt a GTK).

nástroje: pyatspi2.

pyatspi2 podľa môjho názoru obsahuje príliš veľa závislostí ako PyGObject. Samotná technológia je dostupná ako bežná dynamická knižnica libatspi.so. Existuje a Referenčná príručkaPre knižnicu pywinauto plánujeme implementovať podporu AT-SPI týmto spôsobom: načítaním súboru libatspi.so a modulu ctypes. Jediným menším problémom je použitie správnej verzie, pretože sa mierne líšia pre aplikácie GTK+ a Qt. Pravdepodobné vydanie pywinauto 0.7.0 bude obsahovať plnú podporu. Linux možno očakávať v prvej polovici roka 2018.

Apple Accessibility API

MacOS má svoj vlastný automatizačný jazyk AppleScript. Na implementáciu niečoho takého v Pythone samozrejme musíte použiť funkcie z ObjectiveC. Počnúc, zdá sa, s MacOS 10.6 je balík pyobjc zahrnutý v predinštalovanom Pythone. To tiež uľahčí zoznam závislostí pre budúcu podporu v pywinauto.

Nástroje: Okrem jazyka Apple Script stojí za pozornosť ATOMac, aka pyatom. Je to rozhranie kompatibilné s LDTP, ale je to aj samostatná knižnica. Má príklad automatizácie iTunes na macO, ktorú napísal môj študent. Existuje známy problém: flexibilné časovanie nefunguje (metódy waitFor*). Celkovo to však nie je zlé.

Ako začať s pywinauto

Prvým krokom je vyzbrojiť sa inšpektorom objektov GUI (čo sa nazýva špionážny nástroj). Pomôže vám študovať aplikáciu zvnútra: ako je štruktúrovaná hierarchia prvkov, aké vlastnosti sú k dispozícii. Najznámejší inšpektori lokality:

  • Spy++ - súčasťou Visual Studio, vrátane Express alebo Community Edition. Používa Win32 API. Známy je aj jeho klon Informácie o okne AutoIt.
  • Inspect.exe — je zahrnuté v Windows SDK. Ak ho máte nainštalovaný, je na 64-bitovej verzii Windows Nájdete ho v priečinku C:Program Files (x86)Windows Kits<winver>binx64. V samotnom inšpektorovi musíte vybrať režim Automatizácia používateľského rozhrania namiesto MS AA (Active Accessibility, predchodca UI Automation).

Po preskúmaní aplikácie skrz naskrz vyberieme backend, ktorý použijeme. Pri vytváraní objektu Application stačí zadať názov backendu.

  • backend=”win32″ — aj keď sa používa v predvolenom nastavení, funguje dobre s MFC, WTL, VB6 a inými staršími aplikáciami.
  • backend=”uia” — nový backend pre automatizáciu používateľského rozhrania MS: funguje perfektne s WPF a WinForms; vhodný aj pre Delphi a Windows Ukladajte aplikácie; funguje s Qt5 a niektorými aplikáciami Java. A vo všeobecnosti, ak Inspect.exe vidí prvky a ich vlastnosti, potom je tento backend vhodný. V podstate väčšina prehliadačov tiež podporuje automatizáciu používateľského rozhrania (Mozilla štandardne a Chrome vyžaduje pri spustení prepínač príkazového riadka). --force-renderer-accessibilityna zobrazenie prvkov na stránkach v Inspect.exe). Samozrejme, konkurencia so selénom v tejto oblasti je sotva možná. Len ďalší spôsob práce s prehliadačom (môže byť užitočný pri scenári viacerých produktov).

Vstupné body pre automatizáciu

Aplikácia bola dôkladne preskúmaná. Je čas vytvoriť objekt Application a spustiť ho alebo pripojiť k už spustenému. Toto nie je len klon štandardnej triedy subprocess.Popen, konkrétne vstupný objekt, ktorý obmedzuje všetky vaše akcie na hranice procesu. To je veľmi užitočné, ak je spustených niekoľko inštancií aplikácie, ale nechcete sa dotknúť zvyšku.

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

# Опишем окно, которое хотим найти в процессе Notepad.exe
dlg_spec = app.UntitledNotepad
# ждем пока окно реально появится
actionable_dlg = dlg_spec.wait('visible')

Ak chcete spravovať niekoľko aplikácií naraz, táto trieda vám pomôže Desktop. Napríklad v kalkulačke na Win10 je hierarchia prvkov rozložená vo viacerých procesoch (nielen calc.exe). Takže žiadny objekt Desktop nedostatočné.

from subprocess import Popen
from pywinauto import Desktop

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

Koreňový objekt (Application alebo Desktop) je jediné miesto, kde musíte zadať backend. Všetko ostatné transparentne spadá do konceptu „špecifikácia->obal“, o ktorom bude reč neskôr.

Špecifikácie okna/prvku

Toto je základný koncept, na ktorom je postavené rozhranie pywinauto. Okno/prvok môžete popísať zhruba alebo podrobnejšie, aj keď ešte neexistuje alebo je už zatvorené. Špecifikácia okna (objekt Špecifikácia okna) ukladá kritériá, podľa ktorých sa má hľadať skutočné okno alebo prvok.

Príklad podrobnej špecifikácie okna:

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

Samotné vyhľadávanie v okne prebieha volaním metódy .wrapper_object(). Vracia určitý „obal“ pre skutočné okno/prvok alebo hody ElementNotFoundError (niekedy ElementAmbiguousError, ak sa nájde niekoľko prvkov, to znamená, že musíte objasniť kritérium vyhľadávania). Tento „obal“ už vie, ako vykonať nejaké akcie s prvkom alebo z neho prijímať údaje.

Python dokáže skryť hovor .wrapper_object(), takže konečný kód bude kratší. Odporúčame ho používať iba na účely ladenia. Nasledujúce dva riadky robia presne to isté:

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

Existuje mnoho kritérií vyhľadávania pre špecifikáciu okna. Tu je len niekoľko príkladov:

# могут иметь несколько уровней
app.window(title_re='.* - Notepad$').window(class_name='Edit')

# можно комбинировать критерии (как AND) и не ограничиваться одним процессом приложения
dlg = Desktop(backend="uia").Calculator
dlg.window(auto_id='num8Button', control_type='Button')

Zoznam všetkých možných kritérií je vo funkcii docs pywinauto.findwindows.find_elements(…).

Kúzlo prístupu podľa atribútu a kľúča

Python uľahčuje vytváranie špecifikácií okna a dynamické rozpoznávanie atribútov objektov (interne je táto metóda prepísaná __getattribute__). Na názov atribútu sa samozrejme vzťahujú rovnaké obmedzenia ako na názov akejkoľvek premennej (nemôžete vkladať medzery, čiarky ani iné špeciálne znaky). Našťastie pywinauto používa takzvaný vyhľadávací algoritmus „najlepšej zhody“, ktorý je odolný voči preklepom a malým odchýlkam.

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

Ak stále potrebujete reťazce Unicode (napríklad pre ruský jazyk), medzery atď., Môžete pristupovať pomocou kľúča (ako keby to bol bežný slovník):

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

Päť pravidiel pre magické mená

Ako zistiť štandardné magické mená? Tie, ktoré sú k prvku priradené pred vyhľadávaním. Ak ste zadali názov, ktorý je dostatočne podobný štandardu, prvok sa nájde.

  1. Podľa názvu (textu, názvu): app.Properties.OK.click()
  2. Podľa textu a typu prvku: app.Properties.OKButton.click()
  3. Podľa typu a čísla: app.Properties.Button3.click() (mená Button0 и Button1 viazaný na prvý nájdený prvok, Button2 - do druhého a potom v poradí - takto sa to stalo historicky)
  4. Podľa statického textu (vľavo alebo hore) a podľa typu: app.OpenDialog.FileNameEdit.set_text("") (užitočné pre prvky s dynamickým textom)
  5. Podľa typu a textu vo vnútri: app.Properties.TabControlSharing.select("General")

Zvyčajne sa uplatňujú dve alebo tri pravidlá súčasne, zriedka viac. Ak chcete skontrolovať, ktoré konkrétne názvy sú dostupné pre každý prvok, môžete použiť metódu print_control_identifiers(). Dokáže vytlačiť strom prvkov na obrazovku aj do súboru. Pre každý prvok sú vytlačené jeho štandardné magické názvy. Odtiaľ môžete tiež skopírovať a prilepiť podrobnejšie špecifikácie podradených prvkov. Výsledok v skripte bude vyzerať takto:

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

Samotný strom prvkov je zvyčajne pomerne veľká handrička.

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

V niektorých prípadoch môže byť tlač celého stromu pomalá (napríklad v iTunes je na jednej karte až tritisíc prvkov!), ale môžete použiť možnosť depth (hĺbka): depth=1 - samotný prvok, depth=2 - iba bezprostredné deti a pod. Dá sa určiť aj v špecifikáciách pri vytváraní child_window.

príklady

Neustále dopĺňame zoznam príkladov v úložisku. Z nedávnych stojí za zmienku automatizácia sieťového analyzátora WireShark (toto je dobrý príklad aplikácie Qt5; aj keď túto úlohu možno vyriešiť bez GUI, pretože existuje scapy.Sniffer z balíka Python scapy). Existuje aj príklad automatizácie MS Paint s panelom s nástrojmi Ribbon.

Ďalší skvelý príklad, ktorý napísal môj študent: pretiahnutím súboru z explorer.exe na stránku Chrome pre Disk Google (do hlavného úložiska sa presunie o niečo neskôr).

A, samozrejme, príklad prihlásenia sa na odber udalostí klávesnice (klávesové skratky) a myši:
hook_and_listen.py.

Poďakovanie

Osobitné poďakovanie patrí tým, ktorí neustále pomáhajú pri rozvoji projektu. Pre mňa a Valentina Toto je trvalé hobby. Dvaja moji študenti z UNN nedávno obhájili bakalársky titul na túto tému. Alexander výrazne prispel k podpore MS UI Automation a nedávno začal vyrábať automatický generátor kódu založený na princípe „record-playback“ na základe vlastností textu (toto je najkomplexnejšia funkcia), zatiaľ len pre backend „uia“. Ivan vyvíja nový backend pre Linux založené na AT-SPI (moduly mouse и keyboard založené python-xlib - už vo vydaniach 0.6.x).

Keďže už nejaký čas učím špeciálny kurz o automatizácii v Pythone, niektorí študenti magisterského štúdia robia domáce úlohy, implementujú malé funkcie alebo príklady automatizácie. Študenti tiež raz objavili niektoré kľúčové veci vo fáze výskumu. Aj keď niekedy musíte prísne sledovať kvalitu kódu. K tomu výrazne pomáhajú statické analyzátory (QuantifiedCode, Codacy a Landscape) a automatické testy v cloude (služba AppVeyor) s pokrytím kódu okolo 95 %.

Tiež ďakujem všetkým, ktorí zanechávajú recenzie, upozorňujú na chyby a posielajú žiadosti o stiahnutie!

Dodatočné zdroje

Na otázky nadväzujeme tag na StackOverflow (nedávno sa objavil tag v ruskej verzii SO) A podľa kľúčového slova na hriankovači, Tam je Rozhovor v ruskom jazyku na Gitter.

Aktualizujeme každý mesiac hodnotenie open-source knižníc na testovanie GUI. Čo sa týka počtu hviezdičiek na GitHub, rýchlejšie rastú len Autohotkey (majú veľmi veľkú komunitu a dlhú históriu) a PyAutoGUI (hlavne vďaka obľúbenosti kníh od jeho autora Al Sweigarta: „Automate the Boring Stuff with Python” a ďalšie).

Zdroj: hab.com

Kúpte si spoľahlivý hosting pre stránky s DDoS ochranou, VPS VDS servery 🔥 Kúpte si spoľahlivý webhosting s ochranou DDoS, VPS VDS servery | ProHoster