Automatizuokite darbalaukio GUI naudodami Python + pywinauto: kaip susidraugauti su MS UI automatizavimu

Python biblioteka pywinauto — yra atvirojo kodo projektas, skirtas darbalaukio grafinės sąsajos programų automatizavimui WindowsPer pastaruosius dvejus metus ji pridėjo svarbių naujų funkcijų:

  • Palaikymas MS UI automatizavimo technologijai. Sąsaja išlieka ta pati ir dabar palaiko „WinForms“, WPF, Qt5, Windows Parduotuvė (UWP) ir panašiai – beveik viskas, kas yra įjungta Windows.
  • Užpakalinių programų / papildinių sistema (šiuo metu po gaubtu yra du iš jų: numatytasis "win32" ir naujas "uia"). Tada sklandžiai judame kelių platformų link.
  • Win32 kabliukai pelei ir klaviatūrai (karštieji klavišai pagal pyHook dvasią).

Taip pat pateiksime trumpą apžvalgą apie tai, kas yra prieinama atvirojo kodo darbalaukio automatizavimui (nepretenduojant į rimtą palyginimą).

Šis straipsnis yra dalinis pranešimo iš SQA Days 20 konferencijos Minske nuorašas (vaizdo juosta и skaidres), iš dalies rusiška versija Getting Started Guide skirtas pywinauto.

Pradėkime nuo trumpos atvirojo kodo apžvalgos šioje srityje. Darbalaukio GUI programoms viskas yra šiek tiek sudėtingiau nei žiniatinklyje, kuriame yra selenas. Štai pagrindiniai metodai:

Koordinatės metodas

Užkoduokite spustelėjimo taškus, tikimės sėkmingų smūgių.
[+] Kelių platformų, lengva įdiegti.
[+] Nesunku „įrašyti ir atkurti“ bandomuosius įrašus.
[-] Labiausiai nestabili keičiant ekrano skiriamąją gebą, temą, šriftus, langų dydžius ir kt.
[-] Reikalingos didžiulės pagalbos pastangos; dažnai lengviau atkurti testus nuo nulio arba išbandyti rankiniu būdu.
[-] Automatizuoja tik veiksmus; yra ir kitų duomenų tikrinimo ir gavimo būdų.

Įrankiai (keli platforma): autopijos, PyAutoGUI, PyUserInput ir daugelis kitų. Paprastai šią funkciją sudaro sudėtingesni įrankiai (ne visada įvairiose platformose).

Verta pasakyti, kad koordinačių metodas gali papildyti kitus metodus. Pavyzdžiui, tinkintai grafikai galite spustelėti santykines koordinates (viršutiniame kairiajame lango / elemento kampe, o ne visame ekrane) - tai paprastai yra gana patikima, ypač jei atsižvelgiama į lango ilgį / plotį. visą elementą (tada nepakenks skirtingos ekrano raiškos).

Kitas variantas: bandymui paskirkite tik vieną įrenginį su stabiliais nustatymais (ne kelių platformų, bet kai kuriais atvejais tai gerai).

Pamatinio vaizdo atpažinimas

[+] Kelių platformų
[+-] Palyginti patikimas (geriau nei koordinačių metodas), bet vis tiek reikia tam tikrų gudrybių.
[-+] Palyginti lėtai, nes Reikia CPU išteklių atpažinimo algoritmams.
[-] Teksto atpažinimas (OCR), kaip taisyklė, yra iš piršto laužtas => teksto duomenų negalima gauti. Kiek žinau, esami OCR sprendimai nėra labai patikimi tokio tipo užduotims atlikti ir nėra plačiai naudojami (sveikiname komentaruose, jei to dar nėra).

Įrankiai: Sikuli, Lackey (Su Sikuli suderinamas, grynas Python), PyAutoGUI.

Prieinamumo technologija

[+] Patikimiausias metodas, nes leidžia ieškoti pagal tekstą, neatsižvelgiant į tai, kaip jį pateikia sistema ar sistema.
[+] Leidžia išgauti tekstinius duomenis => lengviau patikrinti testo rezultatus.
[+] Paprastai greičiausias, nes beveik nenaudoja procesoriaus resursų.
[-] Sukurti įrankį, veikiantį įvairiose platformose, yra sunku: absoliučiai visos atvirojo kodo bibliotekos palaiko vieną ar dvi prieinamumo technologijas. Windows/Linux/„MacOS“ pilnai nepalaiko niekas, išskyrus mokamas platformas, tokias kaip „TestComplete“, „UFT“ ar „Squish“.
[-] Tokia technologija iš esmės ne visada prieinama. Pavyzdžiui, išbandyti įkėlimo ekraną „VirtualBox“ viduje – to negalima padaryti be vaizdo atpažinimo. Tačiau daugeliu klasikinių atvejų vis dar taikomas prieinamumo metodas. Tai bus aptarta toliau.

Įrankiai: TestStack.White C#, Winium.Desktop C# (suderinamas su selenu), MS WinApp tvarkyklė C# (suderinamas su Appium), pywinauto, pyatom (suderinamas su LDTP) Python-UIAutomation-skirta-Windows, RAutomatika Ruby, LDTP (Linux Darbalaukio testavimo projektas) ir jo Windows versija kobra.

LDTP yra bene vienintelis kelių platformų atvirojo kodo įrankis (tiksliau, bibliotekų šeima), pagrįstas prieinamumo technologijomis. Tačiau jis nėra labai populiarus. Pats jo nenaudojau, bet pagal atsiliepimus jo sąsaja nėra pati patogiausia. Jei turite teigiamų atsiliepimų, pasidalykite jais komentaruose.

Išbandykite užpakalines duris (dar žinomas kaip patalpų dviratis)

Kelių platformų programoms patys kūrėjai dažnai sukuria vidinį mechanizmą, užtikrinantį testavimą. Pavyzdžiui, aplikacijoje sukuria paslaugų TCP serverį, bando prie jo prisijungti ir siunčia tekstines komandas: ką paspausti, kur gauti duomenis ir pan. Patikimas, bet ne universalus.

Pagrindinės darbalaukio pritaikymo neįgaliesiems technologijos

Senas geras Win32 API

Labiausiai Windows programos, parašytos prieš WPF išleidimą ir po jo Windows Store, vienaip ar kitaip yra sukurti naudojant Win32 API. Būtent, MFC, WTL, C++ Builder, Delphi, VB6 – visi šie įrankiai naudoja Win32 API. Net Windows Formos daugiausia suderinamos su „Win32“ API.

Įrankiai: AutoIt (panašus į VB) ir Python įvynioklis pyautoit, AutoHotkey (savo kalba, yra IDispatch COM sąsaja), pywinauto (Python) RAutomatika (rubinas) win32-autogui (Rubinas).

„Microsoft“ vartotojo sąsajos automatizavimas

Pagrindinis privalumas: MS UI automatizavimo technologija palaiko didžiąją daugumą grafinės sąsajos programų Windows Išskyrus retas išimtis. Problema: tai nėra daug lengviau išmokti nei „Win32“ API. Priešingu atveju niekas nekurtų jai apvalkalų.

Tiesą sakant, tai yra pasirinktinių COM sąsajų rinkinys (daugiausia UIAutomationCore.dll), taip pat formoje yra .NET įvynioklis namespace System.Windows.Automation. Beje, jame yra klaida, dėl kurios kai kurie vartotojo sąsajos elementai gali būti praleisti. Todėl geriau naudoti UIAutomationCore.dll tiesiogiai (jei esate girdėję apie UiaComWrapper C#, tada tai yra).

COM sąsajų tipai:

(1) Pagrindinis IUžinomas – „viso blogio šaknis“. Žemiausias lygis, niekada patogus naudoti.
(2) ID siuntimas ir išvestiniai produktai (pvz., Excel.Application), kuris gali būti naudojamas Python naudojant win32com.client paketą (yra įtrauktas į pyWin32). Patogiausias ir gražiausias variantas.
(3) Pasirinktinės sąsajos, su kuriomis gali dirbti trečiosios šalies Python paketas komtipai.

Įrankiai: TestStack.White C#, pywinauto 0.6.0+ Winium.Desktop C#, Python-UIAutomation-skirta-Windows (jų šaltinio kodas, skirtas C paketams per UIAutomationCore.dll, neatskleidžiamas), RAutomatika Rubyne.

AT-SPI

Nepaisant to, kad beveik visos šeimos ašys Linux Sukurta „X Window System“ pagrindu („Fedora 25“ versijoje „X“ pakeitė „Wayland“), „X“ leidžia valdyti tik aukščiausio lygio langus ir pelę / klaviatūrą. Išsamiai mygtukų, sąrašų laukų ir pan. analizei yra AT-SPI technologija. Populiariausi langų tvarkyklės turi vadinamąjį AT-SPI registro demoną, kuris suteikia automatizuotą grafinę sąsają programoms (palaikomos bent Qt ir GTK).

Įrankiai: pyatspi2.

Mano nuomone, pyatspi2 turi per daug priklausomybių, tokių kaip PyGObject. Pati technologija yra įprasta dinamiška biblioteka libatspi.so. Čia yra Žinynas„pywinauto“ bibliotekai planuojame įdiegti AT-SPI palaikymą tokiu būdu: įkeldami libatspi.so ir „ctypes“ modulį. Vienintelė nedidelė problema yra teisingos versijos naudojimas, nes jos šiek tiek skiriasi GTK+ ir Qt programoms. Tikėtina, kad „pywinauto 0.7.0“ versija suteiks visišką palaikymą. Linux galima tikėtis 2018 metų pirmoje pusėje.

Apple Accessibility API

„MacOS“ turi savo automatizavimo kalbą „AppleScript“. Norėdami įdiegti kažką panašaus į Python, žinoma, turite naudoti funkcijas iš ObjectiveC. Atrodo, kad pradedant „MacOS 10.6“, pyobjc paketas yra įtrauktas į iš anksto įdiegtą Python. Tai taip pat palengvins priklausomybių sąrašą, kad ateityje būtų galima palaikyti pywinauto.

Įrankiai: Be Apple Script kalbos, verta atkreipti dėmesį ATOMac, dar žinomas kaip pyatom. Tai sąsaja suderinama su LDTP, bet taip pat yra atskira biblioteka. Tai turi „iTunes“ automatizavimo pavyzdys „MacOs“., parašė mano mokinys. Yra žinoma problema: lankstus laikas neveikia (metodai waitFor*). Bet apskritai tai nėra blogai.

Kaip pradėti naudotis pywinauto

Pirmas žingsnis yra apsiginkluoti GUI objektų inspektoriumi (vadinamu šnipinėjimo įrankiu). Tai padės jums ištirti programą iš vidaus: kaip sudaryta elementų hierarchija, kokios savybės yra prieinamos. Garsiausi svetainių inspektoriai:

  • Šnipas++ - įtraukta į „Visual Studio“, įskaitant „Express“ arba „Community Edition“. Naudoja Win32 API. Taip pat žinomas jo klonas „AutoIt“ lango informacija.
  • Inspect.exe – yra įtrauktas į Windows SDK. Jei jis įdiegtas, vadinasi, jis yra 64 bitų sistemoje. Windows Jį galite rasti aplanke C:Program Files (x86)Windows Kits<winver>binx64. Pačiame inspektoriuje turite pasirinkti režimą UI automatizavimas vietoj MS AA (Active Accessibility, UI automatizavimo protėvis).

Išsamiai išnagrinėję programą, pasirenkame užpakalinę programą, kurią naudosime. Kuriant Application objektą pakanka nurodyti backend pavadinimą.

  • backend=”win32″ - Nors naudojamas pagal numatytuosius nustatymus, gerai veikia su MFC, WTL, VB6 ir kitomis senomis programomis.
  • backend = "uia" — nauja MS UI automatizavimo posistemė: puikiai veikia su WPF ir WinForms; taip pat tinka Delphi ir Windows Programėlių saugykla; veikia su Qt5 ir kai kuriomis „Java“ programomis. Ir apskritai, jei „Inspect.exe“ mato elementus ir jų ypatybes, tai ši posistemė tinka. Iš esmės dauguma naršyklių taip pat palaiko vartotojo sąsajos automatizavimą („Mozilla“ pagal numatytuosius nustatymus, o „Chrome“ reikalauja komandinės eilutės jungiklio paleidžiant). --force-renderer-accessibilitynorėdami pamatyti elementus Inspect.exe puslapiuose). Žinoma, konkurencija su Selenu šioje srityje vargu ar įmanoma. Tik dar vienas būdas dirbti su naršykle (gali būti naudingas kelių produktų scenarijui).

Įėjimo taškai automatizavimui

Paraiška buvo gerai ištirta. Atėjo laikas sukurti programos objektą ir jį paleisti arba pridėti prie jau veikiančio. Tai ne tik standartinės klasės klonas subprocess.Popen, būtent įvesties objektas, apribojantis visus jūsų veiksmus iki proceso ribų. Tai labai naudinga, jei veikia keli programos egzemplioriai, bet nenorite liesti kitų.

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

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

Jei norite valdyti kelias programas vienu metu, ši klasė jums padės Desktop. Pavyzdžiui, Win10 skaičiuoklėje elementų hierarchija yra paskirstyta keliuose procesuose (ne tik calc.exe). Taigi jokio objekto Desktop nepakankamai.

from subprocess import Popen
from pywinauto import Desktop

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

Šakninis objektas (Application arba Desktop) yra vienintelė vieta, kur reikia nurodyti užpakalinę programą. Visa kita aiškiai patenka į „specifikacija-> įvynioklis“ koncepciją, kuri bus aptarta vėliau.

Lango/elemento specifikacijos

Tai yra pagrindinė koncepcija, kuria remiantis sukurta pywinauto sąsaja. Langą/elementą galite apibūdinti apytiksliai arba išsamiau, net jei jo dar nėra arba jis jau uždarytas. Lango specifikacija (objektas Lango specifikacija) išsaugo kriterijus, pagal kuriuos reikia ieškoti tikro lango ar elemento.

Išsamios lango specifikacijos pavyzdys:

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

Pati lango paieška vyksta iškviečiant metodą .wrapper_object(). Tai grąžina tam tikrą „įvyniojimą“ tikram langui / elementui arba išmeta ElementNotFoundError (kartais ElementAmbiguousError, jei randami keli elementai, tai yra, reikia patikslinti paieškos kriterijų). Šis „įvyniotuvas“ jau žino, kaip atlikti kai kuriuos veiksmus su elementu arba gauti iš jo duomenis.

Python gali paslėpti skambutį .wrapper_object(), todėl galutinis kodas tampa trumpesnis. Rekomenduojame jį naudoti tik derinimo tikslais. Kitos dvi eilutės atlieka lygiai tą patį:

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

Yra daug lango specifikacijos paieškos kriterijų. Štai tik keli pavyzdžiai:

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

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

Visų galimų kriterijų sąrašas yra funkcijų dokumentuose pywinauto.findwindows.find_elements(…).

Prieigos magija pagal atributą ir raktą

Python leidžia lengvai kurti lango specifikacijas ir dinamiškai atpažinti objekto atributus (viduje metodas yra nepaisomas __getattribute__). Žinoma, atributo pavadinimui taikomi tokie patys apribojimai kaip ir bet kurio kintamojo pavadinimui (negalite įterpti tarpų, kablelių ar kitų specialiųjų simbolių). Laimei, pywinauto naudoja vadinamąjį „geriausios atitikties“ paieškos algoritmą, kuris yra atsparus rašybos klaidoms ir nedideliems skirtumams.

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

Jei vis dar reikia Unikodo eilučių (pavyzdžiui, rusų kalbai), tarpų ir pan., galite pasiekti klavišu (tarsi tai būtų įprastas žodynas):

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

Penkios stebuklingų vardų taisyklės

Kaip sužinoti standartinius magiškus vardus? Tie, kurie yra priskirti elementui prieš ieškant. Jei nurodėte pavadinimą, kuris yra pakankamai panašus į standartą, elementas bus rastas.

  1. Pagal pavadinimą (tekstą, pavadinimą): app.Properties.OK.click()
  2. Pagal tekstą ir elemento tipą: app.Properties.OKButton.click()
  3. Pagal tipą ir numerį: app.Properties.Button3.click() (vardai Button0 и Button1 susieta su pirmuoju rastu elementu, Button2 - į antrą, o paskui eilės tvarka - taip atsitiko istoriškai)
  4. Pagal statinį tekstą (kairėje arba viršuje) ir pagal tipą: app.OpenDialog.FileNameEdit.set_text("") (naudinga elementams su dinamišku tekstu)
  5. Pagal tipą ir tekstą viduje: app.Properties.TabControlSharing.select("General")

Dažniausiai vienu metu taikomos dvi ar trys taisyklės, retai daugiau. Norėdami patikrinti, kurie konkretūs kiekvieno elemento pavadinimai galimi, galite naudoti šį metodą print_control_identifiers(). Jis gali spausdinti elementų medį tiek į ekraną, tiek į failą. Kiekvienam elementui atspausdinami standartiniai stebuklingi pavadinimai. Taip pat iš ten galite nukopijuoti ir įklijuoti išsamesnes antrinių elementų specifikacijas. Rezultatas scenarijuje atrodys taip:

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

Pats elementų medis dažniausiai yra gana didelė kojytė.

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

Kai kuriais atvejais viso medžio spausdinimas gali būti lėtas (pavyzdžiui, „iTunes“ viename skirtuke yra net trys tūkstančiai elementų!), tačiau galite naudoti parinktį depth (gylis): depth=1 - pats elementas, depth=2 - tik tiesioginiai vaikai ir pan. Kuriant jį taip pat galima nurodyti specifikacijose child_window.

pavyzdžiai

Nuolat pildome saugykloje esančių pavyzdžių sąrašas. Tarp naujausių verta paminėti WireShark tinklo analizatoriaus automatizavimą (tai geras Qt5 programos pavyzdys; nors šią užduotį galima išspręsti ir be GUI, nes yra scapy.Sniffer iš Python paketo niekšiškas). Taip pat yra MS Paint automatizavimo pavyzdys su juostelės įrankių juosta.

Kitas puikus pavyzdys, kurį parašė mano studentė: vilkite failą iš explorer.exe į „Google“ disko „Chrome“ puslapį (šiek tiek vėliau jis persikels į pagrindinę saugyklą).

Ir, žinoma, klaviatūros (karštųjų klavišų) ir pelės įvykių prenumeratos pavyzdys:
hook_and_listen.py.

Padėkos

Ypatingas ačiū tiems, kurie nuolat padeda vystyti projektą. Man ir Valentino Tai nuolatinis hobis. Du mano studentai iš UNN neseniai apgynė bakalauro laipsnius šia tema. Aleksandras labai prisidėjo prie MS UI Automation palaikymo ir neseniai pradėjo kurti automatinį kodų generatorių, pagrįstą „įrašymo atkūrimo“ principu, pagrįstu teksto savybėmis (tai sudėtingiausia funkcija), kol kas tik „uia“ vidiniam įrenginiui. Ivanas kuria naują vidinę sistemą, skirtą Linux remiantis AT-SPI (moduliais mouse и keyboard remiantis python-xlib - jau 0.6.x leidimuose).

Kadangi jau kurį laiką dėstau specialų automatizavimo kursą Python, kai kurie magistrantai atlieka namų darbus, diegia smulkias funkcijas ar automatizavimo pavyzdžius. Kai kuriuos svarbiausius dalykus tyrimo etape taip pat kadaise atskleidė studentai. Nors kartais tenka griežtai stebėti kodo kokybę. Tam labai padeda statiniai analizatoriai (QuantifiedCode, Codacy ir Landscape) ir automatiniai debesyje atliekami testai (AppVeyor paslauga), kurių kodo aprėptis yra maždaug 95%.

Taip pat dėkojame visiems, kurie palieka atsiliepimus, kelia klaidas ir siunčia užklausas!

Papildomi resursai

Mes stebime klausimus žyma „StackOverflow“. (pasirodė neseniai žyma rusiškoje SO versijoje) Ir pagal raktinį žodį Tosteryje. Yra Pokalbis rusų kalba per Gitter.

Mes atnaujiname kiekvieną mėnesį atvirojo kodo bibliotekų, skirtų GUI testavimui, įvertinimas. Kalbant apie žvaigždžių skaičių „GitHub“, greičiau auga tik „Autohotkey“ (jie turi labai didelę bendruomenę ir ilgą istoriją) ir „PyAutoGUI“ (daugiausia dėl jo autoriaus Al Sweigarto knygų populiarumo: „Automatizuokite nuobodžius dalykus naudodami Python“ ir kiti).

Šaltinis: www.habr.com

Pirkite patikimą prieglobą svetainėms su DDoS apsauga, VPS VDS serveriais 🔥 Įsigykite patikimą svetainių talpinimą su DDoS apsauga, VPS VDS serveriais | ProHoster