Python-Bibliothek — ist ein Open-Source-Projekt zur Automatisierung von Desktop-GUI-Anwendungen unter Windows. In den letzten zwei Jahren wurden bedeutende neue Funktionen hinzugefügt:
- Unterstützung der MS UI Automation-Technologie. Die Benutzeroberfläche bleibt dieselbe, und nun werden unterstützt: WinForms, WPF, Qt5, Windows Store (UWP) und so weiter — fast alles, was auf Windows verfügbar ist.
- Ein System von Backends/Plugins (derzeit sind zwei vorhanden: der Standard
"win32"und neu"uia"). Weiter geht es sanft in Richtung Plattformunabhängigkeit. - Win32-Hooks für Maus und Tastatur (Hotkeys im Stil von pyHook).
Wir werden auch einen kurzen Überblick über das geben, was im Open Source für Desktop-Automatisierung verfügbar ist (ohne Anspruch auf ernsthaften Vergleich).
Dieser Artikel ist teilweise eine Transkription des Vortrags von der SQA Days 20 Konferenz in Minsk ( und ), teilweise die russische Version für pywinauto.
- Hauptansätze
- Die wichtigsten Desktop-Barrierefreiheitstechnologien
Wir beginnen mit einem kurzen Überblick über Open Source in diesem Bereich. Für Desktop-GUI-Anwendungen ist alles etwas komplizierter als für das Web, das Selenium besitzt. Hier sind die Hauptansätze:
Koordinatenmethode
Hardcodieren von Klickpunkten, hoffen auf glückliche Treffer.
[+] Plattformunabhängig, leicht umsetzbar.
[+] Einfach, um "Record-Playback"-Testaufzeichnungen zu erstellen.
[-] Am instabilsten gegenüber Änderungen der Bildschirmauflösung, Themen, Schriftarten, Fenstergrößen usw.
[-] Es erfordert enorme Anstrengungen für die Unterstützung; oft ist es einfacher, Tests von Grund auf neu zu generieren oder manuell zu testen.
[-] Automatisiert nur Aktionen; für Überprüfungen und Datenextraktion gibt es andere Methoden.
Werkzeuge (plattformunabhängig): , , und viele andere. In der Regel beinhalten komplexere Werkzeuge diese Funktionalität (nicht immer plattformunabhängig).
Es sei gesagt, dass die Koordinatenmethode die anderen Ansätze ergänzen kann. Zum Beispiel kann man bei benutzerdefinierter Grafik auf relative Koordinaten klicken (vom linken oberen Eck des Fensters/Elements, nicht vom gesamten Bildschirm) — das ist normalerweise ausreichend zuverlässig, insbesondere wenn die Länge/Breite des gesamten Elements berücksichtigt wird (dann stört auch eine andere Bildschirmauflösung nicht).
Eine weitere Option: Nur einen Computer mit stabilen Einstellungen für Tests auswählen (nicht plattformübergreifend, aber in manchen Fällen geeignet).
Erkennung von Referenzbildern
[+] Plattformübergreifend
[+-] Relativ zuverlässig (besser als die Koordinatenmethode), erfordert aber dennoch einige Kniffe.
[-+] Relativ langsam, da CPU-Ressourcen für die Erkennungsalgorithmen benötigt werden.
[-] Bei der Texterkennung (OCR) geht es in der Regel nicht um Sprache => Es können keine Textdaten extrahiert werden. Soweit ich weiß, sind die vorhandenen OCR-Lösungen für diese Art von Aufgaben nicht sehr zuverlässig und finden keine breite Anwendung (Kommentare sind willkommen, wenn sich das bereits geändert hat).
Werkzeuge: , (Sikuli-kompatibel, in reinem Python), .
Barrierefreiheitstechnologien
[+] Die zuverlässigste Methode, da sie die Textsuche unabhängig von der Art der Darstellung durch das System oder Framework ermöglicht.
[+] Ermöglicht die Extraktion von Textdaten => einfacher, um die Testergebnisse zu verifizieren.
[+] In der Regel die schnellste, da sie die CPU-Ressourcen kaum beansprucht.
[-] Es ist schwierig, ein plattformübergreifendes Tool zu erstellen: Alle Open-Source-Bibliotheken unterstützen in der Regel eine oder zwei Zugänglichkeitstechnologien. Windows/Linux/MacOS wird überhaupt nicht von jemandem unterstützt, außer kostenpflichtigen wie TestComplete, UFT oder Squish.
[-] Manchmal ist eine solche Technologie grundsätzlich nicht verfügbar. Zum Beispiel kann das Testen eines Bootbildschirms in VirtualBox nicht ohne Bilderkennung durchgeführt werden. In vielen klassischen Fällen kann jedoch der Zugänglichkeitsansatz angewendet werden. Darum soll es im Folgenden gehen.
Werkzeuge: in C#, in C# (Selenium-kompatibel), in C# (Appium-kompatibel), , (kompatibel mit LDTP), , in Ruby, (Linux Desktop Testing Project) und seine Windows-Version .
LDTP ist wohl das einzige plattformübergreifende Open-Source-Tool (genauer gesagt eine Familie von Bibliotheken), das auf Technologien zur Zugänglichkeit basiert. Es ist jedoch nicht sehr populär. Ich habe es selbst nicht verwendet, aber Berichten zufolge ist das Interface nicht das benutzerfreundlichste. Wenn es positive Rückmeldungen gibt, bitte in den Kommentaren teilen.
Test-Backdoor (auch bekannt als interner Fahrradweg)
Für plattformübergreifende Anwendungen erstellen die Entwickler oft einen internen Mechanismus zur Gewährleistung der Testbarkeit. Zum Beispiel richten sie einen Hilfs-TCP-Server in der Anwendung ein, an den Tests anschließen und Textbefehle senden: was zu klicken ist, woher die Daten stammen usw. Zuverlässig, aber nicht universell.
Die wichtigsten Desktop-Barrierefreiheitstechnologien
Das gute alte Win32 API
Die meisten Windows-Anwendungen, die vor der Einführung von WPF und der Windows Store veröffentlicht wurden, basieren in irgendeiner Weise auf der Win32 API. Insbesondere MFC, WTL, C++ Builder, Delphi, VB6 – all diese Werkzeuge nutzen die Win32 API. Selbst Windows Forms sind in hohem Maße mit der Win32 API kompatibel.
Werkzeuge: (ähnlich wie VB) und Python Wrapper , (eigene Sprache, es gibt eine IDispatch COM-Schnittstelle), (Python), (Ruby), (Ruby).
Microsoft UI Automation
Der große Vorteil: Die MS UI Automation-Technologie unterstützt die überwiegende Mehrheit der GUI-Anwendungen unter Windows mit einigen Ausnahmen. Das Problem: Sie ist nicht viel einfacher zu lernen als die Win32 API. Andernfalls hätte niemand Wrapper dafür erstellt.
Tatsächlich handelt es sich um ein Set von benutzerdefinierten COM-Schnittstellen (vor allem, UIAutomationCore.dll), und es gibt auch ein .NET-Wrapper in Form von namespace System.Windows.Automation. Übrigens hat es einen eingebauten Fehler, aufgrund dessen einige UI-Elemente übersehen werden können. Daher ist es besser, UIAutomationCore.dll direkt zu verwenden (wenn Sie von UiaComWrapper in C# gehört haben, ist das es).
Varianten von COM-Schnittstellen:
(1) Basis-IUnknown — „die Wurzel allen Übels“. Am niedrigsten, absolut nicht benutzerfreundlich.
(2) IDispatch und abgeleitete (zum Beispiel, Excel.Application), die in Python mit dem Paket win32com.client (Teil von pyWin32) verwendet werden können. Die bequemste und ansprechendste Variante.
(3) Benutzerdefinierte Schnittstellen, mit denen das Drittanbieter-Python-Paket .
Werkzeuge: in C#, 0.6.0+, in C#, arbeiten kann (deren Quellcode der C-Wrapper über UIAutomationCore.dll nicht offengelegt ist), in Ruby.
AT-SPI
Trotz der Tatsache, dass fast alle Distributionen der Linux-Familie auf dem X Window System basieren (in Fedora 25 wurden die „X“ auf Wayland umgestellt), ermöglichen die „X“ nur die Bedienung von Fenstern der oberen Ebene sowie der Maus/Tastatur. Für detaillierte Analysen von Schaltflächen, Listenfeldern und so weiter gibt es die AT-SPI-Technologie. Die beliebtesten Window-Manager haben so genannte AT-SPI-Registry-Demonen, die automatisierbare GUIs für Anwendungen bereitstellen (mindestens Qt und GTK werden unterstützt).
Werkzeuge: .
pyatspi2 enthält meiner Meinung nach zu viele Abhängigkeiten wie PyGObject. Die Technologie selbst ist in Form einer normalen dynamischen Bibliothek verfügbar libatspi.so. Dazu gibt es . Für die Bibliothek pywinauto planen wir, die Unterstützung für AT-SPI genau so zu implementieren: durch das Laden von libatspi.so und dem ctypes-Modul. Es gibt nur ein kleines Problem bei der Verwendung der richtigen Version, da diese für GTK+ und Qt-Anwendungen etwas unterschiedlich ist. Die Veröffentlichung von pywinauto 0.7.0 mit umfassender Unterstützung für Linux könnte in der ersten Hälfte des Jahres 2018 erwartet werden.
Apple Accessibility API
Auf MacOS gibt es eine eigene Automatisierungssprache namens AppleScript. Um etwas Ähnliches in Python umzusetzen, müssen natürlich Funktionen aus Objective-C verwendet werden. Seit MacOS 10.6 wird das Paket pyobjc mit dem vorinstallierten Python geliefert. Dies erleichtert auch die Liste der Abhängigkeiten für die zukünftige Unterstützung in pywinauto.
Werkzeuge: Neben der Apple Script-Sprache sollte man auf , auch bekannt als pyatom, achten. Es ist in Bezug auf die Schnittstelle mit LDTP kompatibel, stellt jedoch auch eine eigenständige Bibliothek dar. Darauf gibt es ein , das von einem meiner Studenten geschrieben wurde. Es gibt ein bekanntes Problem: flexible Timings funktionieren nicht (Methoden waitFor*). Aber insgesamt ist es eine gute Sache.
Wie man mit pywinauto arbeitet
Zuerst sollte man sich mit einem GUI-Objektinspektor ausstatten (das, was man als Spy-Tool bezeichnet). Er hilft, die Anwendung von innen zu erkunden: wie die Hierarchie der Elemente aufgebaut ist und welche Eigenschaften verfügbar sind. Die bekanntesten Objektinspektoren sind:
- Spy++ — ist im Lieferumfang von Visual Studio enthalten, einschließlich Express oder Community Edition. Verwendet die Win32 API. Auch bekannt ist sein Klon AutoIt Window Info.
- Inspect.exe — ist im Windows SDK enthalten. Wenn es installiert ist, kann man es auf einem 64-Bit-Windows im Ordner
C:Program Files (x86)Windows Kitsbinx64finden. Im Inspektor selbst muss man den Modus UI Automation anstatt MS AA (Active Accessibility, Vorläufer von UI Automation) auswählen.
Nachdem die Anwendung gründlich untersucht wurde, wählen wir den Backend, den wir verwenden möchten. Es reicht aus, den Namen des Backends beim Erstellen des Application-Objekts anzugeben.
- backend=»win32″ — wird vorerst als Standard verwendet und funktioniert gut mit MFC, WTL, VB6 und anderen Legacy-Anwendungen.
- backend=»uia» — ein neuer Backend für MS UI Automation: funktioniert ideal mit WPF und WinForms; auch gut für Delphi und Windows Store-Anwendungen; funktioniert mit Qt5 und einigen Java-Anwendungen. Und generell, wenn Inspect.exe Elemente und deren Eigenschaften sieht, dann ist dieser Backend geeignet. Prinzipiell unterstützen die meisten Browser ebenfalls UI Automation (Mozilla standardmäßig, während Chrome beim Start den Command-Line-Parameter
--force-renderer-accessibilitybenötigt, um die Elemente auf den Seiten in Inspect.exe sichtbar zu machen). Natürlich ist ein Wettbewerb mit Selenium in diesem Bereich kaum möglich. Es ist einfach eine weitere Möglichkeit, mit dem Browser zu arbeiten (kann für plattformübergreifende Szenarien nützlich sein).
Einstiegspunkte für die Automatisierung
Die Anwendung ist ausreichend erforscht. Es ist Zeit, ein Application-Objekt zu erstellen und es zu starten oder sich mit einem bereits gestarteten zu verbinden. Es ist nicht einfach ein Klon der standardmäßigen Klasse subprocess.Popen, nämlich das Eingangsobjekt, das all Ihre Aktionen innerhalb der Grenzen des Prozesses einschränkt. Dies ist äußerst nützlich, wenn mehrere Instanzen der Anwendung gestartet sind und die anderen nicht berührt werden sollen.
from pywinauto.application import Application
app = Application(backend="uia").start('notepad.exe')
# Beschreiben wir das Fenster, das wir im Prozess Notepad.exe finden möchten
dlg_spec = app.UntitledNotepad
# warten, bis das Fenster tatsächlich erscheint
actionable_dlg = dlg_spec.wait('visible')Wenn Sie mehrere Anwendungen gleichzeitig steuern möchten, hilft Ihnen die Klasse Desktop. Zum Beispiel ist in der Windows 10-Rechner-App die Hierarchie der Elemente über mehrere Prozesse verteilt (nicht nur calc.exe). Daher kommt man ohne das Objekt Desktop nicht aus.
from subprocess import Popen
from pywinauto import Desktop
Popen('calc.exe', shell=True)
dlg = Desktop(backend="uia").Calculator
dlg.wait('visible')Das Wurzelobjekt (Anwendung oder Desktop) ist der einzige Ort, an dem der Backend angegeben werden muss. Alles andere fügt sich nahtlos in das Konzept „Spezifikation->Wrapper“ ein, das im Folgenden erklärt wird.
Spezifikationen von Fenstern/Elementen
Dies ist das grundlegende Konzept, auf dem die pywinauto-Schnittstelle basiert. Sie können das Fenster/Element grob oder detaillierter beschreiben, selbst wenn es noch nicht existiert oder bereits geschlossen ist. Die Fensterspezifikation (Objekt WindowSpecification) speichert die Kriterien, nach denen das tatsächliche Fenster oder Element gesucht werden muss.
Beispiel für eine detaillierte Fensterspezifikation:
>>> dlg_spec = app.window(title='Untitled - Notepad')
>>> dlg_spec
>>> dlg_spec.wrapper_object()Die Suche nach dem Fenster erfolgt durch den Aufruf der Methode .wrapper_object(). Sie gibt einen „Wrapper“ für das tatsächliche Fenster/Element zurück oder wirft einen ElementNotFoundError (manchmal ElementAmbiguousError, wenn mehrere Elemente gefunden wurden, d.h. es müssen weitere Suchkriterien präzisiert werden). Dieser „Wrapper“ kann bereits einige Aktionen mit dem Element durchführen oder Daten daraus abrufen.
Python kann den Aufruf .wrapper_object()verbergen, sodass der finale Code kürzer wird. Wir empfehlen, ihn nur zu Debugging-Zwecken zu verwenden. Die folgenden beiden Zeilen erledigen absolut dasselbe:
dlg_spec.wrapper_object().minimize() # Debugging
dlg_spec.minimize() # ProduktionEs gibt viele Suchkriterien für die Fensterspezifikation. Hier sind 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 Dokumenten der Funktion .
Die Magie des Zugriffs über Attribute und Schlüssel
Python erleichtert die Erstellung von Fensterspezifikationen und erkennt die Attribute des Objekts dynamisch (innerhalb ist die Methode __getattribute__). Natürlich gelten für den Namen des Attributs die gleichen Einschränkungen wie für den Namen jeder Variablen (Leerzeichen, Kommas und andere Sonderzeichen sind nicht erlaubt). Glücklicherweise verwendet pywinauto einen sogenannten „Best Match“-Suchalgorithmus, der gegenüber Tippfehlern und kleinen Variationen resistent ist.
app.UntitledNotepad
# ist dasselbe wie
app.window(best_match='UntitledNotepad')Wenn dennoch Unicode-Zeichenfolgen benötigt werden (zum Beispiel für die russische Sprache), Leerzeichen usw., kann auf den Schlüssel zugegriffen werden (als wäre es ein gewöhnliches Wörterbuch):
app['Untitled - Notepad']
# ist dasselbe wie
app.window(best_match='Untitled - Notepad')Fünf Regeln für magische Namen
Wie erfährt man die Referenz-Magic-Namen? Die, die dem Element vor der Suche zugewiesen werden. Wenn Sie einen Namen angegeben haben, der der Referenz ziemlich ähnlich ist, wird das Element gefunden.
- Nach Titel (Text, Name):
app.Properties.OK.click() - Nach Text und Elementtyp:
app.Properties.OKButton.click() - Nach Typ und Nummer:
app.Properties.Button3.click()(NamenButton0undButton1sind an das erste gefundene Element gebunden,Button2— an das zweite, und weiter der Reihe nach — das ist historisch bedingt) - 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 innerhalb:
app.Properties.TabControlSharing.select("General")
In der Regel werden zwei oder drei Regeln gleichzeitig angewendet, selten mehr. Um zu überprüfen, welche spezifischen Namen für jedes Element verfügbar sind, kann die Methode print_control_identifiers(). Sie kann die Elementstruktur sowohl auf dem Bildschirm als auch in einer Datei ausgeben. Für jedes Element werden seine Referenz-Magic-Namen ausgedruckt. Außerdem können detailliertere Spezifikationen der untergeordneten Elemente von dort kopiert werden. Das Ergebnis im Skript sieht so aus:
app.Properties.child_window(title="Contains:", auto_id="13087", control_type="Edit")Die Struktur der Elemente selbst — in der Regel ein ziemlich langes Dokument.
>>> app.Properties.print_control_identifiers()
Steuerelement-Identifikatoren:
Dialog - 'Windows NT-Eigenschaften' (L688, T518, R1065, B1006)
[u'Windows NT-Eigenschaftendialog', u'Dialog', u'Windows NT-Eigenschaften']
child_window(title="Windows NT-Eigenschaften", control_type="Window")
|
| Bild - '' (L717, T589, R749, B622)
| [u'', u'0', u'Bild1', u'Bild0', 'Bild', u'1']
| child_window(auto_id="13057", control_type="Image")
|
| Bild - '' (L717, T630, R1035, B632)
| ['Bild2', u'2']
| child_window(auto_id="13095", control_type="Image")
|
| Bearbeiten - 'Ordnername:' (L790, T596, R1036, B619)
| [u'3', 'Bearbeiten', u'Bearbeiten1', u'Bearbeiten0']
| child_window(title="Ordnername:", auto_id="13156", control_type="Edit")
|
| Statisch - 'Typ:' (L717, T643, R780, B658)
| [u'Typ:Statisch', u'Statisch', u'Statisch1', u'Statisch0', u'Typ:']
| child_window(title="Typ:", auto_id="13080", control_type="Text")
|
| Bearbeiten - 'Typ:' (L790, T643, R1036, B666)
| [u'4', 'Bearbeiten2', u'Typ:Bearbeiten']
| child_window(title="Typ:", auto_id="13059", control_type="Edit")
|
| Statisch - 'Standort:' (L717, T669, R780, B684)
| [u'Standort:Statisch', u'Standort:', u'Statisch2']
| child_window(title="Standort:", auto_id="13089", control_type="Text")
|
| Bearbeiten - 'Standort:' (L790, T669, R1036, B692)
| ['Bearbeiten3', u'Standort:Bearbeiten', u'5']
| child_window(title="Standort:", auto_id="13065", control_type="Edit")
|
| Statisch - 'Größe:' (L717, T695, R780, B710)
| [u'Größe:Statisch', u'Größe:', u'Statisch3']
| child_window(title="Größe:", auto_id="13081", control_type="Text")
|
| Bearbeiten - 'Größe:' (L790, T695, R1036, B718)
| ['Bearbeiten4', u'6', u'Größe:Bearbeiten']
| child_window(title="Größe:", auto_id="13064", control_type="Edit")
|
| Statisch - 'Größe auf Diskette:' (L717, T721, R780, B736)
| [u'Größe auf Diskette:', u'Größe auf Diskette:Statisch', u'Statisch4']
| child_window(title="Größe auf Diskette:", auto_id="13107", control_type="Text")
|
| Bearbeiten - 'Größe auf Diskette:' (L790, T721, R1036, B744)
| ['Bearbeiten5', u'7', u'Größe auf Diskette:Bearbeiten']
| child_window(title="Größe auf Diskette:", auto_id="13106", control_type="Edit")
|
| Statisch - 'Enthält:' (L717, T747, R780, B762)
| [u'Enthält:1', u'Enthält:0', u'Enthält:Statisch', u'Statisch5', u'Enthält:']
| child_window(title="Enthält:", auto_id="13088", control_type="Text")
|
| Bearbeiten - 'Enthält:' (L790, T747, R1036, B770)
| [u'8', 'Bearbeiten6', u'Enthält:Bearbeiten']
| child_window(title="Enthält:", auto_id="13087", control_type="Edit")
|
| Bild - 'Enthält:' (L717, T773, R1035, B775)
| [u'Enthält:Bild', 'Bild3', u'Enthält:2']
| child_window(title="Enthält:", auto_id="13096", control_type="Image")
|
| Statisch - 'Erstellt:' (L717, T786, R780, B801)
| [u'Erstellt:', u'Erstellt:Statisch', u'Statisch6', u'Erstellt:1', u'Erstellt:0']
| child_window(title="Erstellt:", auto_id="13092", control_type="Text")
|
| Bearbeiten - 'Erstellt:' (L790, T786, R1036, B809)
| [u'Erstellt:Bearbeiten', 'Bearbeiten7', u'9']
| child_window(title="Erstellt:", auto_id="13072", control_type="Edit")
|
| Bild - 'Erstellt:' (L717, T812, R1035, B814)
| [u'Erstellt:Bild', 'Bild4', u'Erstellt:2']
| child_window(title="Erstellt:", auto_id="13097", control_type="Image")
|
| Statisch - 'Attribute:' (L717, T825, R780, B840)
| [u'Attribute:Statisch', u'Statisch7', u'Attribute:']
| child_window(title="Attribute:", auto_id="13091", control_type="Text")
|
| Kontrollkästchen - 'Schreibgeschützt (Gilt nur für Dateien im Ordner)' (L790, T825, R1035, B841)
| [u'Kontrollkästchen0', u'Kontrollkästchen1', 'Kontrollkästchen', u'Schreibgeschützt (Gilt nur für Dateien im Ordner)Kontrollkästchen', u'Schreibgeschützt (Gilt nur für Dateien im Ordner)']
| child_window(title="Schreibgeschützt (Gilt nur für Dateien im Ordner)", auto_id="13075", control_type="CheckBox")
|
| Kontrollkästchen - 'Versteckt' (L790, T848, R865, B864)
| ['Kontrollkästchen2', u'VerstecktKontrollkästchen', u'Versteckt']
| child_window(title="Versteckt", auto_id="13076", control_type="CheckBox")
|
| Schaltfläche - 'Erweiterte...' (L930, T845, R1035, B868)
| [u'Erweiterte...', u'Erweiterte...Schaltfläche', 'Schaltfläche', u'Schaltfläche1', u'Schaltfläche0']
| child_window(title="Erweiterte...", auto_id="13154", control_type="Button")
|
| Schaltfläche - 'OK' (L814, T968, R889, B991)
| ['Schaltfläche2', u'OK', u'OKSchaltfläche']
| child_window(title="OK", auto_id="1", control_type="Button")
|
| Schaltfläche - 'Abbrechen' (L895, T968, R970, B991)
| ['Schaltfläche3', u'AbbrechenSchaltfläche', u'Abbrechen']
| child_window(title="Abbrechen", auto_id="2", control_type="Button")
|
| Schaltfläche - 'Übernehmen' (L976, T968, R1051, B991)
| ['Schaltfläche4', u'ÜbernehmenSchaltfläche', u'Übernehmen']
| child_window(title="Übernehmen", auto_id="12321", control_type="Button")
|
| TabControl - '' (L702, T556, R1051, B962)
| [u'10', u'TabControlFreigabe', u'TabControlFrühere Versionen', u'TabControlSicherheit', u'TabControl', u'TabControlAnpassen']
| child_window(auto_id="12320", control_type="Tab")
| |
| | TabItem - 'Allgemein' (L704, T558, R753, B576)
| | [u'AllgemeinTabItem', 'TabItem', u'Allgemein', u'TabItem0', u'TabItem1']
| | child_window(title="Allgemein", control_type="TabItem")
| |
| | TabItem - 'Freigabe' (L753, T558, R801, B576)
| | [u'Freigabe', u'FreigabeTabItem', 'TabItem2']
| | child_window(title="Freigabe", control_type="TabItem")
| |
| | TabItem - 'Sicherheit' (L801, T558, R851, B576)
| | [u'Sicherheit', 'TabItem3', u'SicherheitTabItem']
| | child_window(title="Sicherheit", control_type="TabItem")
| |
| | TabItem - 'Frühere Versionen' (L851, T558, R947, B576)
| | [u'Frühere VersionenTabItem', u'Frühere Versionen', 'TabItem4']
| | child_window(title="Frühere Versionen", control_type="TabItem")
| |
| | TabItem - 'Anpassen' (L947, T558, R1007, B576)
| | [u'AnpassenTabItem', 'TabItem5', u'Anpassen']
| | child_window(title="Anpassen", control_type="TabItem")
|
| Titelzeile - 'Keine' (L712, T521, R1057, B549)
| ['Titelzeile', u'11']
| |
| | Menü - 'System' (L696, T526, R718, B548)
| | [u'System0', u'System', u'System1', u'Menü', u'SystemMenü']
| | child_window(title="System", auto_id="Menüleiste", control_type="MenuBar")
| | |
| | | Menüpunkt - 'System' (L696, T526, R718, B548)
| | | [u'System2', u'Menüpunkt', u'SystemMenüpunkt']
| | | child_window(title="System", control_type="MenuItem")
| |
| | Schaltfläche - 'Schließen' (L1024, T519, R1058, B549)
| | [u'SchließenSchaltfläche', u'Schließen', 'Schaltfläche5']
| | child_window(title="Schließen", control_type="Button")In einigen Fällen kann das Drucken des gesamten Baums verlangsamen (zum Beispiel in iTunes, wo auf einem Tab bis zu drei Tausend Elemente vorhanden sind!), aber man kann den Parameter depth (Tiefe): depth=1 — das Element selbst, depth=2 — nur direkte Kinder, und so weiter. Dies kann man auch in den Spezifikationen beim Erstellen angeben child_window.
Beispiele
Wir erweitern ständig . Von den neuesten Beispielen ist die Automatisierung des Netzwerkmonitors WireShark zu erwähnen (das ist ein gutes Beispiel für eine Qt5-Anwendung; obwohl man diese Aufgabe auch ohne GUI lösen kann, denn es gibt scapy.Sniffer aus dem Python-Paket ). Außerdem gibt es ein Beispiel zur Automatisierung von MS Paint mit seiner Ribbon-Toolbar.
Ein weiteres großartiges Beispiel, das von meinem Studenten geschrieben wurde: (es wird etwas später ins Hauptrepository verschoben).
Und natürlich ein Beispiel für das Abonnieren von Tastaturereignissen (Hotkeys) und Mausereignissen:
.
Dank
Ein besonderer Dank geht an diejenigen, die ständig helfen, das Projekt weiterzuentwickeln. Für mich und ist es ein dauerhaftes Hobby. Zwei meiner Studenten von der NNSTU haben kürzlich ihre Bachelorarbeiten zu diesem Thema verteidigt. hat einen großen Beitrag zur Unterstützung von MS UI Automation geleistet und begonnen, einen automatischen Codegenerator nach dem Prinzip „Aufzeichnen-Wiedergabe“ auf der Grundlage von Texteigenschaften zu erstellen (das ist das komplizierteste Feature), vorerst nur für den „uia“-Backend. entwickelt einen neuen Backend für Linux auf Basis von AT-SPI (Module mouse und keyboard basierend auf — bereits in den Versionen 0.6.x).
Da ich schon lange einen Spezialkurs über Automatisierung in Python gebe, führen einige Masterstudenten ihre Hausarbeiten durch, indem sie kleine Features oder Automatisierungsbeispiele implementieren. Einige wichtige Dinge in der Forschungsphase wurden ebenfalls einst von Studenten entdeckt. Obwohl manchmal die Qualität des Codes streng überwacht werden muss. Dabei helfen statische Analysatoren (QuantifiedCode, Codacy und Landscape) und automatische Tests in der Cloud (Dienst AppVeyor) mit einer Codeabdeckung von etwa 95%.
Ein Dankeschön auch an alle, die Rückmeldungen hinterlassen, Bugs melden und Pull-Anfragen senden!
Zusätzliche Ressourcen
Bei Fragen verfolgen wir diese über (vor kurzem erschien ) und . Es gibt .
Jeden Monat aktualisieren wir . Nur Autohotkey (mit einer sehr großen Community und langer Geschichte) und PyAutoGUI (hauptsächlich dank der beliebten Bücher seines Autors Al Sweigart: „Automate the Boring Stuff with Python“ und anderer) wachsen auf GitHub schneller in Bezug auf die Anzahl der Sterne.
Quelle: habr.com
