Python-Bibliothek ist ein Open-Source-Projekt zur Automatisierung von Desktop-GUI-Anwendungen unter Windows. In den letzten zwei Jahren sind darin neue Hauptfunktionen aufgetaucht:
- Unterstützung für die MS UI-Automatisierungstechnologie. Die Schnittstelle ist dieselbe und unterstützt jetzt: WinForms, WPF, Qt5, Windows Store (UWP) usw. – fast alles, was unter Windows verfügbar ist.
- System von Backends/Plugins (derzeit befinden sich zwei davon unter der Haube: Standard).
"win32"und ein neues"uia"). Dann bewegen wir uns reibungslos in Richtung Cross-Plattform. - Win32-Hooks für Maus und Tastatur (Hotkeys im Sinne von pyHook).
Außerdem geben wir einen kurzen Überblick darüber, was in Open Source für die Desktop-Automatisierung verfügbar ist (ohne den Anspruch auf einen seriösen Vergleich zu erheben).
Dieser Artikel ist eine teilweise Abschrift eines Berichts von der SQA Days 20-Konferenz in Minsk ( и ), teilweise russische Version für pywinauto.
- Grundlegende Ansätze
- Grundlegende Desktop-Barrierefreiheitstechnologien
Beginnen wir mit einem kurzen Überblick über Open Source in diesem Bereich. Bei Desktop-GUI-Anwendungen ist alles etwas komplizierter als beim Web, das über Selenium verfügt. Hier sind die wichtigsten Ansätze:
koordinieren methode
Codieren Sie die Klickpunkte fest, wir hoffen auf erfolgreiche Treffer.
[+] Plattformübergreifend, einfach zu implementieren.
[+] Es ist einfach, Testaufnahmen „aufzuzeichnen und wiederzugeben“.
[-] Am instabilsten gegenüber Änderungen der Bildschirmauflösung, des Designs, der Schriftarten, der Fenstergrößen usw.
[-] Es ist ein enormer Supportaufwand erforderlich; es ist oft einfacher, Tests von Grund auf neu zu generieren oder manuell zu testen.
[-] Automatisiert nur Aktionen; es gibt andere Methoden zum Überprüfen und Abrufen von Daten.
Tools (plattformübergreifend): , , und viele andere. In der Regel umfassen komplexere Tools diese Funktionalität (nicht immer plattformübergreifend).
Es ist erwähnenswert, dass die Koordinatenmethode andere Ansätze ergänzen kann. Bei benutzerdefinierten Grafiken können Sie beispielsweise auf relative Koordinaten klicken (in der oberen linken Ecke des Fensters/Elements und nicht auf dem gesamten Bildschirm) – dies ist normalerweise recht zuverlässig, insbesondere wenn Sie die Länge/Breite berücksichtigen gesamtes Element (dann schaden unterschiedliche Bildschirmauflösungen nicht).
Eine weitere Option: Nur eine Maschine mit stabilen Einstellungen zum Testen zuweisen (nicht plattformübergreifend, aber in manchen Fällen ist es gut).
Referenzbilderkennung
[+] Plattformübergreifend[+-] Relativ zuverlässig (besser als die Koordinatenmethode), erfordert aber dennoch einige Tricks.
[-+] Relativ langsam, weil Erfordert CPU-Ressourcen für Erkennungsalgorithmen.
[-] Texterkennung (OCR) kommt in der Regel nicht in Frage => Textdaten können nicht ermittelt werden. Soweit ich weiß, sind bestehende OCR-Lösungen für diese Art von Aufgaben nicht sehr zuverlässig und werden nicht häufig verwendet (willkommen in den Kommentaren, falls dies nicht bereits der Fall ist).
Werkzeuge: , (Sikuli-kompatibel, reines Python), .
Barrierefreiheitstechnologie
[+] Die zuverlässigste Methode, weil ermöglicht Ihnen die Suche nach Text, unabhängig davon, wie dieser vom System oder Framework gerendert wird.[+] Ermöglicht das Extrahieren von Textdaten => einfachere Überprüfung der Testergebnisse.
[+] In der Regel der Schnellste, weil verbraucht fast keine CPU-Ressourcen.
[-] Es ist schwierig, ein plattformübergreifendes Tool zu erstellen: Absolut alle Open-Source-Bibliotheken unterstützen eine oder zwei Barrierefreiheitstechnologien. Windows/Linux/MacOS wird von niemandem vollständig unterstützt, außer von kostenpflichtigen Programmen wie TestComplete, UFT oder Squish.
[-] Eine solche Technologie ist grundsätzlich nicht immer verfügbar. Testen Sie beispielsweise den Ladebildschirm in VirtualBox – ohne Bilderkennung ist dies nicht möglich. In vielen klassischen Fällen ist der Barrierefreiheitsansatz jedoch immer noch anwendbar. Dies wird weiter besprochen.
Werkzeuge: in C#, in C# (Selenium-kompatibel), in C# (Appium-kompatibel), , (LDTP-kompatibel) , in Rubin, (Linux Desktop Testing Project) und seine Windows-Version .
LDTP ist möglicherweise das einzige plattformübergreifende Open-Source-Tool (genauer gesagt eine Familie von Bibliotheken), das auf Barrierefreiheitstechnologien basiert. Allerdings ist es nicht sehr beliebt. Ich habe es selbst nicht verwendet, aber laut Rezensionen ist die Benutzeroberfläche nicht die bequemste. Wenn Sie positives Feedback haben, teilen Sie es bitte in den Kommentaren mit.
Testen Sie die Hintertür (auch bekannt als Indoor-Bike)
Bei plattformübergreifenden Anwendungen erstellen die Entwickler häufig selbst einen internen Mechanismus, um die Testbarkeit sicherzustellen. Sie erstellen beispielsweise einen Dienst-TCP-Server in der Anwendung, testen eine Verbindung zu diesem und senden Textbefehle: worauf man klicken muss, wo man die Daten bekommt usw. Zuverlässig, aber nicht universell.
Grundlegende Desktop-Barrierefreiheitstechnologien
Gute alte Win32-API
Die meisten Windows-Anwendungen, die vor der Veröffentlichung von WPF und dann des Windows Store geschrieben wurden, wurden auf die eine oder andere Weise auf der Win32-API erstellt. Nämlich MFC, WTL, C++ Builder, Delphi, VB6 – alle diese Tools verwenden die Win32-API. Sogar Windows Forms sind weitgehend mit der Win32-API kompatibel.
Werkzeuge: (ähnlich VB) und Python-Wrapper , (eigene Sprache, es gibt eine IDispatch COM-Schnittstelle), (Python) (Rubin) (Rubin).
Microsoft-UI-Automatisierung
Der Hauptvorteil: Die MS UI-Automatisierungstechnologie unterstützt mit wenigen Ausnahmen die überwiegende Mehrheit der GUI-Anwendungen unter Windows. Problem: Es ist nicht viel einfacher zu erlernen als die Win32-API. Sonst würde niemand Verpackungen darüber machen.
Tatsächlich handelt es sich hierbei um eine Reihe benutzerdefinierter COM-Schnittstellen (hauptsächlich UIAutomationCore.dll) und verfügt außerdem über einen .NET-Wrapper im Formular namespace System.Windows.Automation. Es gibt übrigens einen Fehler, der dazu führen kann, dass einige Elemente der Benutzeroberfläche fehlen. Daher ist es besser, UIAutomationCore.dll direkt zu verwenden (wenn Sie von UiaComWrapper in C# gehört haben, dann ist es das Richtige).
Arten von COM-Schnittstellen:
(1) Grundlegendes Wissen – „die Wurzel allen Übels“. Die niedrigste Stufe, niemals benutzerfreundlich.
(2) IDispatch und Derivate (z. B Excel.Application), das in Python mithilfe des Pakets win32com.client (im Lieferumfang von pyWin32 enthalten) verwendet werden kann. Die bequemste und schönste Option.
(3) Benutzerdefinierte Schnittstellen, mit denen ein Python-Paket eines Drittanbieters arbeiten kann .
Werkzeuge: in C#, 0.6.0 + in C#, (Ihr Quellcode für die C-Wrapper über UIAutomationCore.dll wird nicht offengelegt), in Ruby.
AT-SPI
Trotz der Tatsache, dass fast alle Achsen der Linux-Familie auf dem X-Window-System basieren (in Fedora 25 wurden die „X“ in Wayland geändert), ermöglichen Ihnen die „X“ die Bedienung nur von Fenstern der obersten Ebene und der Maus/ Tastatur. Für eine detaillierte Analyse von Schaltflächen, Listenfeldern usw. gibt es die AT-SPI-Technologie. Die beliebtesten Fenstermanager verfügen über einen sogenannten AT-SPI-Registry-Daemon, der eine automatisierte GUI für Anwendungen bereitstellt (mindestens Qt und GTK werden unterstützt).
Werkzeuge: .
pyatspi2 enthält meiner Meinung nach zu viele Abhängigkeiten wie PyGObject. Die Technologie selbst ist als reguläre dynamische Bibliothek verfügbar libatspi.so. Da ist ein . Für die pywinauto-Bibliothek planen wir, die AT-SPI-Unterstützung auf diese Weise zu implementieren: durch Laden von libatspi.so und dem ctypes-Modul. Lediglich bei der Verwendung der erforderlichen Version gibt es ein kleines Problem, da diese bei GTK+- und Qt-Anwendungen leicht unterschiedlich sind. Mit der voraussichtlichen Veröffentlichung von pywinauto 0.7.0 mit vollständiger Linux-Unterstützung ist im ersten Halbjahr 2018 zu rechnen.
Apple Accessibility API
MacOS verfügt über eine eigene Automatisierungssprache, AppleScript. Um so etwas in Python zu implementieren, müssen Sie natürlich Funktionen von ObjectiveC verwenden. Ab MacOS 10.6 scheint das Paket pyobjc im vorinstallierten Python enthalten zu sein. Dadurch wird es auch einfacher, Abhängigkeiten für die zukünftige Unterstützung in pywinauto aufzulisten.
Tools: Neben der Apple Script-Sprache lohnt es sich, darauf zu achten , auch bekannt als Pyatom. Sie ist schnittstellenkompatibel mit LDTP, aber auch eine eigenständige Bibliothek. Es hat , geschrieben von meinem Schüler. Es gibt ein bekanntes Problem: Flexible Zeiteinteilung funktioniert nicht (Methoden waitFor*). Aber im Großen und Ganzen keine schlechte Sache.
So starten Sie mit pywinauto
Der erste Schritt besteht darin, sich mit einem GUI-Objektinspektor (einem sogenannten Spy-Tool) auszustatten. Es wird Ihnen helfen, die Anwendung von innen zu studieren: wie die Hierarchie der Elemente strukturiert ist und welche Eigenschaften verfügbar sind. Die bekanntesten Bauinspektoren:
- Spion++ – in Visual Studio enthalten, einschließlich Express oder Community Edition. Verwendet die Win32-API. Auch sein Klon ist bekannt AutoIt-Fensterinformationen.
- Inspect.exe - im Windows SDK enthalten. Wenn Sie es installiert haben, finden Sie es unter 64-Bit-Windows im Ordner
C:Program Files (x86)Windows Kits<winver>binx64. Im Inspektor selbst müssen Sie einen Modus auswählen UI-Automatisierung anstelle von MS AA (Active Accessibility, Vorfahr der UI-Automatisierung).
Nachdem wir die Anwendung gründlich geprüft haben, wählen wir das Backend aus, das wir verwenden werden. Es reicht aus, beim Erstellen des Anwendungsobjekts den Namen des Backends anzugeben.
- backend=“win32“ – Funktioniert bei standardmäßiger Verwendung gut mit MFC, WTL, VB6 und anderen älteren Anwendungen.
- backend=“uia“ — neues Backend für MS UI Automation: funktioniert perfekt mit WPF und WinForms; auch gut für Delphi- und Windows Store-Anwendungen; Funktioniert mit Qt5 und einigen Java-Anwendungen. Und im Allgemeinen ist dieses Backend geeignet, wenn Inspect.exe die Elemente und ihre Eigenschaften sieht. Grundsätzlich unterstützen die meisten Browser auch die UI-Automatisierung (Mozilla standardmäßig, und Chrome muss beim Start mit der Befehlszeilentaste gefüttert werden).
--force-renderer-accessibilityum Elemente auf Seiten in Inspect.exe anzuzeigen). Natürlich ist eine Konkurrenz zu Selen in diesem Bereich kaum möglich. Nur eine weitere Möglichkeit, mit dem Browser zu arbeiten (kann für ein produktübergreifendes Szenario nützlich sein).
Einstiegspunkte für die Automatisierung
Die Anwendung wurde umfassend recherchiert. Es ist an der Zeit, ein Anwendungsobjekt zu erstellen und es auszuführen oder an ein bereits ausgeführtes Objekt anzuhängen. Dies ist nicht nur ein Klon einer Standardklasse subprocess.Popen, nämlich ein Eingabeobjekt, das alle Ihre Aktionen auf die Grenzen des Prozesses beschränkt. Dies ist sehr nützlich, wenn mehrere Instanzen der Anwendung ausgeführt werden, Sie den Rest aber nicht berühren möchten.
from pywinauto.application import Application
app = Application(backend="uia").start('notepad.exe')
# Опишем окно, которое хотим найти в процессе Notepad.exe
dlg_spec = app.UntitledNotepad
# ждем пока окно реально появится
actionable_dlg = dlg_spec.wait('visible')Wenn Sie mehrere Anwendungen gleichzeitig verwalten möchten, hilft Ihnen dieser Kurs Desktop. Beispielsweise ist in einem Rechner unter Win10 die Hierarchie der Elemente auf mehrere Prozesse verteilt (nicht nur calc.exe). Also kein Gegenstand Desktop nicht genug
from subprocess import Popen
from pywinauto import Desktop
Popen('calc.exe', shell=True)
dlg = Desktop(backend="uia").Calculator
dlg.wait('visible')Stammobjekt (Application oder Desktop) ist der einzige Ort, an dem Sie das Backend angeben müssen. Alles andere fällt transparent in das „Spezifikation->Wrapper“-Konzept, auf das später noch eingegangen wird.
Fenster-/Elementspezifikationen
Dies ist das Kernkonzept, auf dem die Pywinauto-Schnittstelle basiert. Sie können ein Fenster/Element grob oder detaillierter beschreiben, auch wenn es noch nicht existiert oder bereits geschlossen ist. Fensterspezifikation (Objekt Fensterspezifikation) speichert die Kriterien, nach denen nach einem echten Fenster oder Element gesucht werden soll.
Beispiel einer detaillierten Fensterspezifikation:
>>> 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>Die Fenstersuche selbst erfolgt durch den Aufruf der Methode .wrapper_object(). Es gibt einen bestimmten „Wrapper“ für ein echtes Fenster/Element oder Würfe zurück ElementNotFoundError (manchmal ElementAmbiguousError, wenn mehrere Elemente gefunden werden, d. h. Sie müssen das Suchkriterium klären). Dieser „Wrapper“ weiß bereits, wie er einige Aktionen mit einem Element ausführt oder Daten von ihm empfängt.
Python kann den Aufruf verbergen .wrapper_object(), sodass der endgültige Code kürzer wird. Wir empfehlen, es nur zu Debugzwecken zu verwenden. Die nächsten beiden Zeilen bewirken genau das Gleiche:
dlg_spec.wrapper_object().minimize() # debugging
dlg_spec.minimize() # productionEs gibt viele Suchkriterien für eine Fensterspezifikation. Hier nur einige Beispiele:
# могут иметь несколько уровней
app.window(title_re='.* - Notepad$').window(class_name='Edit')
# можно комбинировать критерии (как AND) и не ограничиваться одним процессом приложения
dlg = Desktop(backend="uia").Calculator
dlg.window(auto_id='num8Button', control_type='Button')Eine Liste aller möglichen Kriterien finden Sie in den Funktionsdokumenten .
Die Magie des Zugriffs per Attribut und Schlüssel
Mit Python ist es einfach, Fensterspezifikationen zu erstellen und Objektattribute dynamisch zu erkennen (intern wird die Methode überschrieben). __getattribute__). Natürlich gelten für den Attributnamen die gleichen Einschränkungen wie für den Namen einer beliebigen Variablen (Sie können keine Leerzeichen, Kommas oder andere Sonderzeichen einfügen). Glücklicherweise verwendet pywinauto einen sogenannten „Best Match“-Suchalgorithmus, der gegen Tippfehler und kleine Abweichungen resistent ist.
app.UntitledNotepad
# то же самое, что
app.window(best_match='UntitledNotepad')Wenn Sie noch Unicode-Zeichenfolgen (z. B. für die russische Sprache), Leerzeichen usw. benötigen, können Sie per Schlüssel darauf zugreifen (als wäre es ein normales Wörterbuch):
app['Untitled - Notepad']
# то же самое, что
app.window(best_match='Untitled - Notepad')Fünf Regeln für magische Namen
Wie finde ich Standard-Magienamen heraus? Diejenigen, die dem Element vor der Suche zugewiesen werden. Wenn Sie einen Namen angegeben haben, der dem Standard hinreichend ähnlich ist, wird das Element gefunden.
- Nach Titel (Text, Name):
app.Properties.OK.click() - Nach Text und nach Elementtyp:
app.Properties.OKButton.click() - Nach Typ und Anzahl:
app.Properties.Button3.click()(NamenButton0иButton1an das erste gefundene Element gebunden,Button2- auf die Sekunde genau und dann der Reihe nach - so geschah es historisch) - Nach statischem Text (links oder oben) und nach Typ:
app.OpenDialog.FileNameEdit.set_text("")(nützlich für Elemente mit dynamischem Text) - Nach Typ und Text darin:
app.Properties.TabControlSharing.select("General")
Normalerweise werden zwei oder drei Regeln gleichzeitig angewendet, selten mehr. Um zu überprüfen, welche spezifischen Namen für jedes Element verfügbar sind, können Sie die Methode verwenden print_control_identifiers(). Es kann einen Baum von Elementen sowohl auf dem Bildschirm als auch in einer Datei drucken. Für jedes Element werden seine standardmäßigen magischen Namen gedruckt. Sie können von dort auch detailliertere Spezifikationen der untergeordneten Elemente kopieren und einfügen. Das Ergebnis im Skript sieht folgendermaßen aus:
app.Properties.child_window(data-gt-translate-attributes='["title"]' title="Contains:", auto_id="13087", control_type="Edit")Der Baum der Elemente selbst ist normalerweise ein ziemlich großes Fußtuch.
>>> 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")In einigen Fällen kann das Drucken des gesamten Baums langsam sein (in iTunes befinden sich beispielsweise bis zu dreitausend Elemente auf einer Registerkarte!), aber Sie können diese Option verwenden depth (Tiefe): depth=1 - das Element selbst, depth=2 - nur unmittelbare Kinder und so weiter. Es kann auch bei der Erstellung in den Spezifikationen angegeben werden child_window.
Примеры
Wir füllen ständig nach . Unter den jüngsten ist die Automatisierung des WireShark-Netzwerkanalysators hervorzuheben (dies ist ein gutes Beispiel für eine Qt5-Anwendung; obwohl diese Aufgabe ohne GUI gelöst werden kann, weil es eine gibt). scapy.Sniffer aus dem Python-Paket ). Es gibt auch ein Beispiel für die Automatisierung von MS Paint mit seiner Multifunktionsleisten-Symbolleiste.
Ein weiteres großartiges Beispiel, das von einem meiner Studenten geschrieben wurde: (es wird etwas später in das Haupt-Repository verschoben).
Und natürlich ein Beispiel für das Abonnieren von Tastatur- (Hotkeys) und Mausereignissen:
.
Danksagung
Besonderer Dank geht an diejenigen, die das Projekt ständig weiterentwickeln. Für mich und Dies ist ein dauerhaftes Hobby. Zwei meiner Studenten von der UNN haben kürzlich ihren Bachelor-Abschluss zu diesem Thema verteidigt. leistete einen großen Beitrag zur Unterstützung von MS UI Automation und begann vor kurzem mit der Entwicklung eines automatischen Codegenerators, der auf dem „Record-Playback“-Prinzip basiert und auf Texteigenschaften basiert (dies ist die komplexeste Funktion), bisher nur für das „uia“-Backend. entwickelt ein neues Backend für Linux auf Basis von AT-SPI (Module mouse и keyboard aufgrund - bereits in Releases 0.6.x).
Da ich seit geraumer Zeit einen speziellen Kurs zum Thema Automatisierung in Python unterrichte, machen einige Masterstudenten Hausaufgaben und implementieren kleine Funktionen oder Beispiele für Automatisierung. Einige wichtige Dinge in der Forschungsphase wurden auch einmal von Studenten entdeckt. Allerdings muss man manchmal die Qualität des Codes streng überwachen. Dabei helfen statische Analysatoren (QuantifiedCode, Codacy und Landscape) und automatische Tests in der Cloud (AppVeyor-Dienst) mit einer Codeabdeckung von rund 95 %.
Vielen Dank auch an alle, die Bewertungen hinterlassen, Fehler melden und Pull-Anfragen senden!
Zusätzliche Ressourcen
Wir gehen den Fragen nach (kürzlich erschienen ) Und . Gibt es .
Wir aktualisieren jeden Monat . Was die Anzahl der Sterne auf GitHub angeht, wachsen nur Autohotkey (sie haben eine sehr große Community und eine lange Geschichte) und PyAutoGUI schneller (hauptsächlich aufgrund der Popularität der Bücher seines Autors Al Sweigart: „Automate the Boring Stuff with“) Python“ und andere).
Source: habr.com
