pywinauto Pythonã©ã€ãã©ãªã¯ãWindowsã§ãã¹ã¯ãããGUIã¢ããªã±ãŒã·ã§ã³ãèªååããããã®ãªãŒãã³ãœãŒã¹ãããžã§ã¯ãã§ãã éå»2幎éã§ãæ°ããäž»èŠãªæ©èœãç»å ŽããŸããã
- MS UI Automationãã¯ãããžãŒã®ãµããŒãã ã€ã³ã¿ãŒãã§ã€ã¹ã¯åãã§ãçŸåšãµããŒããããŠããŸãïŒWinFormsãWPFãQt5ãWindowsã¹ãã¢ïŒUWPïŒãªã©-Windowsã«ããã»ãšãã©ãã¹ãŠã®ãã®ã
- ããã¯ãšã³ã/ãã©ã°ã€ã³ã®ã·ã¹ãã ïŒçŸåšããããã®ãã¡ã®2ã€ã
"uia"
ãããŸãïŒããã©ã«ãã®"win32"
ãšæ°ãã"uia"
ïŒã ãã®åŸãã¯ãã¹ãã©ãããã©ãŒã ã«åããŠã¹ã ãŒãºã«ç§»è¡ããŸãã - Win32ããŠã¹ããã³ããŒããŒãããã¯ïŒpyKookã¹ã¿ã€ã«ã®ãããããŒïŒã
ãŸãããã¹ã¯ããããªãŒãã¡ãŒã·ã§ã³ã®ãªãŒãã³ãœãŒã¹ã§å©çšå¯èœãªãã®ã«ã€ããŠç°¡åãªã¬ãã¥ãŒãè¡ããŸãïŒçå£ãªæ¯èŒã®äž»åŒµã¯ãããŸããïŒã
ãã®èšäºã®äžéšã¯ããã³ã¹ã¯ã§ã®SQA Days 20ã«ã³ãã¡ã¬ã³ã¹ã®ã¬ããŒãã®åãã§ãïŒ ãããªãšã¹ã©ã€ã ïŒãäžéšã¯pywinautoã®å ¥éã¬ã€ãã®ãã·ã¢èªçã§ãã
- äž»ãªã¢ãããŒã
- äž»èŠãªãã¹ã¯ãããã¢ã¯ã»ã·ããªãã£ãã¯ãããžãŒ
- pywinautoãéå§ããæ¹æ³
ãã®åéã®ãªãŒãã³ãœãŒã¹ã®æŠèŠããå§ããŸãããã ãã¹ã¯ãããGUIã¢ããªã±ãŒã·ã§ã³ã®å Žåããã¹ãŠãSeleniumãåããWebãããããè€éã§ãã äž»ãªã¢ãããŒãã¯æ¬¡ã®ãšããã§ãã
åº§æšæ³
ã¯ãªãã¯ãã€ã³ããããŒãã³ãŒãããè¯ãããããæåŸ
ããŸãã
[+]ã¯ãã¹ãã©ãããã©ãŒã ãå®è£
ãç°¡åã
[+]èšé²åçãã¹ãèšé²ãç°¡åã«èšé²ã§ããŸãã
[-]ç»é¢ã®è§£å床ãããŒãããã©ã³ãããŠã£ã³ããŠãµã€ãºãªã©ã倿Žããã®ã«æãäžå®å®ã§ãã
[-]å€å€§ãªãµããŒãåªåãå¿
èŠã§ããå€ãã®å Žåããã¹ããæåããåçæããããæåã§ãã¹ãããæ¹ãç°¡åã§ãã
[-]ã¢ã¯ã·ã§ã³ã®ã¿ãèªååããŸã;ããŒã¿ãæ€èšŒããã³ååŸããä»ã®æ¹æ³ããããŸãã
ããŒã«ïŒã¯ãã¹ãã©ãããã©ãŒã ïŒïŒ autopy ã PyAutoGUI ã PyUserInputãªã©ã éåžžãããé«åºŠãªããŒã«ã«ã¯ãã®æ©èœãå«ãŸããŸãïŒåžžã«ã¯ãã¹ãã©ãããã©ãŒã ã§ã¯ãããŸããïŒã
åº§æšæ³ã¯ä»ã®ã¢ãããŒããè£å®ã§ãããšèšã䟡å€ããããŸãã ããšãã°ãã«ã¹ã¿ã ã°ã©ãã£ãã¯ã¹ã®å ŽåãïŒç»é¢å šäœã§ã¯ãªããŠã£ã³ããŠ/èŠçŽ ã®å·Šäžé ããïŒçžå¯Ÿåº§æšãã¯ãªãã¯ã§ããŸã-ããã¯éåžžãç¹ã«èŠçŽ å šäœã®é·ã/å¹ ãèæ ®ãããšéåžžã«ä¿¡é Œæ§ãé«ããªããŸãïŒç°ãªãç»é¢è§£ååºŠã¯æãªãããŸããïŒã
å¥ã®ãªãã·ã§ã³ïŒå®å®ããèšå®ïŒã¯ãã¹ãã©ãããã©ãŒã ã§ã¯ãªããå Žåã«ãã£ãŠã¯é©åïŒã§1å°ã®ãã·ã³ã®ã¿ããã¹ãããããã«å²ãåœãŠãã
åç §ç»åèªè
[+]ã¯ãã¹ãã©ãããã©ãŒã
[+-]æ¯èŒçä¿¡é Œæ§ãé«ãïŒåº§æšæ³ãããåªããŠããŸãïŒããäŸç¶ãšããŠããªãã¯ãå¿
èŠã§ãã
[-+]æ¯èŒçé
ã èªèã¢ã«ãŽãªãºã ã«ã¯CPUãªãœãŒã¹ãå¿
èŠã§ãã
[-]ååãšããŠãããã¹ãèªèïŒOCRïŒã¯åé¡å€ã§ã=>ããã¹ãããŒã¿ãååŸã§ããŸããã ç§ã®ç¥ãéããæ¢åã®OCRãœãªã¥ãŒã·ã§ã³ã¯ãã®ã¿ã€ãã®ã¿ã¹ã¯ã«ã¯ããŸãä¿¡é Œæ§ããªããåºã䜿çšãããŠããŸããïŒæ¢ã«ããã§ãªãå Žåã¯ã³ã¡ã³ããæè¿ããŸãïŒã
ããŒã«ïŒ Sikuli ã Lackey ïŒSikuliäºæãçŽç²ãªPythonïŒã PyAutoGUI ã
ã¢ã¯ã»ã·ããªãã£æè¡
[+]æãä¿¡é Œã§ããæ¹æ³ã ã·ã¹ãã ãŸãã¯ãã¬ãŒã ã¯ãŒã¯ã«ãã£ãŠã¬ã³ããªã³ã°ãããæ¹æ³ã«é¢ä¿ãªããããã¹ãã§æ€çŽ¢ã§ããŸãã
[+]ããã¹ãããŒã¿ãæœåºã§ããŸã=>ãã¹ãçµæã確èªããã®ãç°¡åã§ãã
[+]ååãšããŠãæéã ã»ãšãã©CPUãªãœãŒã¹ãæ¶è²»ããŸããã
[-]ã¯ãã¹ãã©ãããã©ãŒã ããŒã«ãäœæããããšã¯å°é£ã§ãã絶察ã«ãã¹ãŠã®ãªãŒãã³ãœãŒã¹ã©ã€ãã©ãªã1ã€ãŸãã¯2ã€ã®ã¢ã¯ã»ã·ããªãã£ãã¯ãããžããµããŒãããŸãã Windows / Linux / MacOSã¯ãTestCompleteãUFTããŸãã¯Squishãªã©ã®ææã®ãã®ä»¥å€ã§ã¯å®å
šã«ãµããŒããããŠããŸããã
[-]ãã®ãããªæè¡ã¯ãååãšããŠåžžã«å©çšã§ãããšã¯éããŸããã ããšãã°ãVirtualBoxå
ã§ããŒãç»é¢ããã¹ãããŸã-ããã§ã¯ãç»åèªèãªãã§ã¯å®è¡ã§ããŸããã ãã ããå€ãã®å€å
žçãªã±ãŒã¹ã§ã¯ãã¢ã¯ã»ã·ããªãã£ã¢ãããŒããé©çšãããŸãã 圌ã¯ããã«è°è«ãããŸãã
ããŒã«ïŒCïŒã®TestStack.White ãCïŒã®Winium.Desktop ïŒSeleniumäºæïŒãCïŒã®MS WinAppDriver ïŒAppiumäºæïŒã pywinauto ã pyatom ïŒ LDTPãšäºæïŒã Python-UIAutomation-for-Windows ãRubyã®RAutomation ã LDTP ïŒ Linux Desktop Testing ProjectïŒããã³ãã®WindowsããŒãžã§ã³ã®Cobra ã
LDTPã¯ãã¢ã¯ã»ã·ããªãã£æè¡ã«åºã¥ãããããããå¯äžã®ã¯ãã¹ãã©ãããã©ãŒã ã®ãªãŒãã³ãœãŒã¹ããŒã«ïŒããæ£ç¢ºã«ã¯ãã©ã€ãã©ãªã®ãã¡ããªãŒïŒã§ãã ãã ããããŸã人æ°ã¯ãããŸããã ç§ã¯èªåã§äœ¿çšããŸããã§ããããã¬ãã¥ãŒã«ãããšããã®ã€ã³ã¿ãŒãã§ãŒã¹ã¯æã䟿å©ã§ã¯ãããŸããã è¯å®çãªã¬ãã¥ãŒãããå Žåã¯ãã³ã¡ã³ãã§å ±æããŠãã ããã
ããã¯ãã¢ã®ãã¹ãïŒå¥åã€ã³ããŒãã€ã¯ïŒ
ã¯ãã¹ãã©ãããã©ãŒã ã¢ããªã±ãŒã·ã§ã³ã®å Žåãéçºè èªèº«ãå éšã¡ã«ããºã ãäœæããŠãã¹ãå®¹ææ§ãæäŸããããšããããããŸãã ããšãã°ãã¢ããªã±ãŒã·ã§ã³ã§ãµãŒãã¹TCPãµãŒããŒãäœæãããã¹ãTCPã«æ¥ç¶ããããã¹ãã³ãã³ããéä¿¡ããŸããã¯ãªãã¯ãããã®ãããŒã¿ãååŸããå Žæãªã©ã ä¿¡é Œã§ããŸãããæ®éçã§ã¯ãããŸããã
äž»èŠãªãã¹ã¯ãããã¢ã¯ã»ã·ããªãã£ãã¯ãããžãŒ
å€ãè¯ãWin32 API
WPFã®ãªãªãŒã¹åã«äœæãããWindowsã¢ããªã±ãŒã·ã§ã³ã®ã»ãšãã©ã¯ãWin32 APIã䜿çšããŠæ§ç¯ãããŸãã ã€ãŸããMFCãWTLãC ++ BuilderãDelphiãVB6-ããããã¹ãŠã®ããŒã«ã¯Win32 APIã䜿çšããŸãã Windows Formsã§ãããäž»ã«Win32 APIäºæã§ãã
ããŒã«ïŒ AutoIt ïŒVBã«é¡äŒŒïŒããã³Pythonã©ãããŒpyautoit ã AutoHotkey ïŒãã€ãã£ãèšèªãIDispatch COMã€ã³ã¿ãŒãã§ã€ã¹ããããŸãïŒã pywinauto ïŒPythonïŒã RAutomation ïŒRubyïŒã win32-autogui ïŒRubyïŒã
Microsoft UIãªãŒãã¡ãŒã·ã§ã³
äž»ãªå©ç¹ïŒMS UIãªãŒãã¡ãŒã·ã§ã³ãã¯ãããžã¯ãã»ãšãã©ã®Windows GUIã¢ããªã±ãŒã·ã§ã³ãã»ãšãã©äŸå€ãªããµããŒãããŸãã åé¡ïŒWin32 APIãããç°¡åã«åŠã¶ããšã¯ã§ããŸããã ããã§ãªããã°ã誰ããããã©ããããªãã£ãã§ãããã
å®éãããã¯ã«ã¹ã¿ã COMã€ã³ã¿ãŒãã§ã€ã¹ïŒäž»ã«UIAutomationCore.dll ïŒã®ã»ããã§ããã namespace System.Windows.Automation
圢åŒã®.NETã·ã§ã«ãæã£ãŠããŸãã ãšããã§ãããã€ãã®UIèŠçŽ ãã¹ããããããå¯èœæ§ãããããããã°ãå°å
¥ãããŠããŸãã ãããã£ãŠãUIAutomationCore.dllãçŽæ¥äœ¿çšããããšããå§ãããŸãïŒCïŒã§UiaComWrapperã«ã€ããŠèããå Žåããããããã§ãïŒã
COMã€ã³ã¿ãŒãã§ã€ã¹ã®çš®é¡ïŒ
ïŒ1ïŒåºç€ãšãªãIUknownã¯ããã¹ãŠã®æªã®æ ¹æºãã§ãã æäœã¬ãã«ã決ããŠãŠãŒã¶ãŒãã¬ã³ããªãŒã§ã¯ãããŸããã
ïŒ2ïŒPythonã§win32com.clientããã±ãŒãžïŒpyWin32ã«ä»å±ïŒã䜿çšããŠäœ¿çšã§ããIDispatchããã³æŽŸçç©ïŒ Excel.Application
ãªã©ïŒã æã䟿å©ã§çŸãããªãã·ã§ã³ã
ïŒ3ïŒãµãŒãããŒãã£ã®Python comtypesããã±ãŒãžã§äœ¿çšã§ããã«ã¹ã¿ã ã€ã³ã¿ãŒãã§ã€ã¹ã
ããŒã«ïŒCïŒã®TestStack.Whiteã pywinauto 0.6.0 + ãCïŒã®Winium.Desktop ã Python-UIAutomation-for-Windows ïŒUIAutomationCore.dllã®ã©ãããŒã©ãããŒã®ãœãŒã¹ã³ãŒããéããªãïŒãRubyã®RAutomation ã
AT-SPI
Linuxãã¡ããªãŒã®ã»ãŒãã¹ãŠã®è»žãX Window Systemã§æ§ç¯ãããŠãããšããäºå®ã«ããããããïŒFedora 25ã§ã¯ãXãã¯Waylandã«å€æŽãããŸããïŒããXãã§ã¯ãããã¬ãã«ãŠã£ã³ããŠãšããŠã¹/ããŒããŒãã®ã¿ã§æäœã§ããŸãã ãã¿ã³ãã·ãŒãããã¯ã¹ãªã©ã®è©³çްãªåæã«ã¯ãAT-SPIãã¯ãããžããããŸãã æãäžè¬çãªãŠã£ã³ããŠãããŒãžã£ã«ã¯ãAT-SPIã¬ãžã¹ããªããŒã¢ã³ãšåŒã°ãããã®ããããã¢ããªã±ãŒã·ã§ã³çšã®èªåGUIãæäŸããŸãïŒå°ãªããšãQtãšGTKããµããŒããããŠããŸãïŒã
ããŒã«ïŒ pyatspi2
ç§ã®æèŠã§ã¯ãpyatspi2ã«ã¯PyGObjectã®ãããªäŸåé¢ä¿ãå€ãããŸãã ãã¯ãããžãŒèªäœã¯ãéåžžã®åçã©ã€ãã©ãªlibatspi.so
圢åŒã§å©çšã§ããŸãã ãªãã¡ã¬ã³ã¹ããã¥ã¢ã«ããããŸãã pywinautoã©ã€ãã©ãªã®å Žåãæ¬¡ã®ããã«AT-SPIãµããŒããå®è£
ããäºå®ã§ããlibatspi.soããŠã³ããŒãããã³ctypesã¢ãžã¥ãŒã«ãä»ããŠã GTK +ãšQtã¢ããªã±ãŒã·ã§ã³ã§ã¯ãããã«ç°ãªããããé©åãªããŒãžã§ã³ã䜿çšããå Žåã«ã®ã¿å°ããªåé¡ããããŸãã Linuxãå®å
šã«ãµããŒãããpywinauto 0.7.0ã®ãªãªãŒã¹ã¯ã2018幎ååã«äºå®ãããŠããŸãã
Apple Accessibility API
MacOSã«ã¯ç¬èªã®AppleScriptãªãŒãã¡ãŒã·ã§ã³èšèªããããŸãã ãã¡ãããPythonã§åæ§ã®ãã®ãå®è£ ããã«ã¯ãObjectiveCã®é¢æ°ã䜿çšããå¿ èŠããããŸãã MacOS 10.6以éãpyobjcããã±ãŒãžã¯ããªã€ã³ã¹ããŒã«ãããpythonã«å«ãŸããŠããŸãã ããã«ãããpywinautoã§å°æ¥ãµããŒãããããã®äŸåé¢ä¿ãªã¹ãã容æã«ãªããŸãã
ããŒã«ïŒApple Scriptèšèªã«å ããŠã ATOMac ïŒå¥åpyatomïŒã«ã泚æããå¿
èŠããããŸãã LDTPãšäºææ§ã®ããã€ã³ã¿ãŒãã§ã€ã¹ã§ãããã¹ã¿ã³ãã¢ãã³ã©ã€ãã©ãªã§ããããŸãã ç§ã®åŠçãæžããmacOã§ã®iTunesãªãŒãã¡ãŒã·ã§ã³ã®äŸããããŸã ã æ¢ç¥ã®åé¡ããããŸãïŒæè»ãªã¿ã€ãã³ã°ãæ©èœããŸããïŒ waitFor*
ã¡ãœããïŒã ããããäžè¬çã«ã¯è¯ãããšã§ãã
pywinautoãéå§ããæ¹æ³
æåã®ã¹ãããã¯ãGUIãªããžã§ã¯ãã®ã€ã³ã¹ãã¯ã¿ãŒïŒããããã¹ãã€ããŒã«ïŒãè£ åããããšã§ãã å éšããã¢ããªã±ãŒã·ã§ã³ã調æ»ããã®ã«åœ¹ç«ã¡ãŸããèŠçŽ ã®éå±€ã®é çœ®æ¹æ³ã䜿çšå¯èœãªããããã£ã æãæåãªãªããžã§ã¯ãæ€æ»å®ïŒ
- Spy ++ -ExpressãŸãã¯Community Editionãå«ãVisual Studioã«å«ãŸããŠããŸãã Win32 APIã䜿çšããŸãã AutoIt Window Infoããã®ã¯ããŒã³ã§ç¥ãããŠããŸãã
- Inspect.exe -Windows SDKã«å«ãŸããŠããŸãã ã€ã³ã¹ããŒã«æžã¿ã®å Žåã64ãããWindowsã§ã¯ããã©ã«ããŒ
C:\Program Files (x86)\Windows Kits\<winver>\bin\x64
ãŸãã ã€ã³ã¹ãã¯ã¿èªäœã§ãMS AAïŒã¢ã¯ãã£ãã¢ã¯ã»ã·ããªãã£ãUIãªãŒãã¡ãŒã·ã§ã³ã®ç¥å ïŒã§ã¯ãªãUIãªãŒãã¡ãŒã·ã§ã³ã¢ãŒããéžæããå¿ èŠããããŸãã
ã¢ããªã±ãŒã·ã§ã³ã培åºçã«åçºãã䜿çšããããã¯ãšã³ããéžæããŸãã Applicationãªããžã§ã¯ãã®äœææã«ããã¯ãšã³ãã®ååãæå®ããã ãã§ååã§ãã
- backend = "win32" -ããã©ã«ãã§äœ¿çšãããŸãããMFCãWTLãVB6ãããã³ãã®ä»ã®ã¬ã¬ã·ãŒã¢ããªã±ãŒã·ã§ã³ã§ããŸãæ©èœããŸãã
- backend = "uia" -MS UIãªãŒãã¡ãŒã·ã§ã³ã®æ°ããããã¯ãšã³ãïŒWPFããã³WinFormsãšå®å
šã«é£æºããŸãã Delphiããã³Windowsã¹ãã¢ã¢ããªã«ãé©ããŠããŸãã Qt5ããã³äžéšã®Javaã¢ããªã±ãŒã·ã§ã³ã§åäœããŸãã äžè¬ã«ãInspect.exeãèŠçŽ ãšãã®ããããã£ãèŠãå Žåããã®ããã¯ãšã³ããé©ããŠããŸãã ååãšããŠãã»ãšãã©ã®ãã©ãŠã¶ãŒã¯UIãªãŒãã¡ãŒã·ã§ã³ããµããŒãããŠããŸãïŒMozillaãããã©ã«ãã§ãããChromeã¯èµ·åæã«ã³ãã³ãã©ã€ã³
--force-renderer-accessibility
ããã£ãŒãããŠInspect.exeã®ããŒãžã®ã¢ã€ãã ã衚瀺ããå¿ èŠããããŸãïŒã ãã¡ããããã®åéã§ã®ã»ã¬ã³ãšã®ç«¶äºã¯ã»ãšãã©äžå¯èœã§ãã ãã©ãŠã¶ãŒãæäœãããã1ã€ã®æ¹æ³ïŒè£œåéã®ã·ããªãªã§ã¯äŸ¿å©ãããããŸããïŒã
èªååã®ãšã³ããªãã€ã³ã
ã¢ããªã±ãŒã·ã§ã³ã¯ããçè§£ãããŠããŸãã Applicationãªããžã§ã¯ããäœæããŠèµ·åãããããã§ã«å®è¡äžã®ãªããžã§ã¯ãã«åå ããŸãã ããã¯ãæšæºã®subprocess.Popen
ã¯ã©ã¹ã®åãªãã¯ããŒã³ã§ã¯ãªãããã¹ãŠã®ã¢ã¯ã·ã§ã³ãããã»ã¹ã®å¢çã«å¶éããå°å
¥ãªããžã§ã¯ãã§ãã ããã¯ãã¢ããªã±ãŒã·ã§ã³ã®è€æ°ã®ã€ã³ã¹ã¿ã³ã¹ãå®è¡ãããŠããããæ®ãã®ã€ã³ã¹ã¿ã³ã¹ã«ã¯æãå ããããªãå Žåã«éåžžã«äŸ¿å©ã§ãã
from pywinauto.application import Application app = Application(backend="uia").start('notepad.exe') # , Notepad.exe dlg_spec = app.UntitledNotepad # actionable_dlg = dlg_spec.wait('visible')
äžåºŠã«è€æ°ã®ã¢ããªã±ãŒã·ã§ã³ã管çããå Žåã¯ã Desktop
ã¯ã©ã¹ã圹ç«ã¡ãŸãã ããšãã°ãWin10ã®èšç®æ©ã§ã¯ãèŠçŽ ã®éå±€ãïŒ calc.exe
ã ãã§ãªãïŒè€æ°ã®ããã»ã¹ã«åºãã£ãŠãcalc.exe
ã ãã®ããã Desktop
ãªããžã§ã¯ãããªããã°ã§ããŸããã
from subprocess import Popen from pywinauto import Desktop Popen('calc.exe', shell=True) dlg = Desktop(backend="uia").Calculator dlg.wait('visible')
ã«ãŒããªããžã§ã¯ãïŒ Application
ãŸãã¯Desktop
ïŒã¯ãããã¯ãšã³ããæå®ããå¿
èŠãããå¯äžã®å Žæã§ãã ãã以å€ã®ãã¹ãŠã¯ãã仿§->ã©ãããŒãã®æŠå¿µã§ééçã«èŠå®ãããŠããŸããããã«ã€ããŠã¯ããã«èª¬æããŸãã
ãŠã£ã³ããŠ/ã¢ã€ãã ã®ä»æ§
ããã¯ãpywinautoã€ã³ã¿ãŒãã§ãŒã¹ãæ§ç¯ãããåºæ¬æŠå¿µã§ãã ãŠã£ã³ããŠ/èŠçŽ ã¯ãååšããªãå Žåãæ¢ã«éããŠããå Žåã§ãããããããŸãã¯ãã詳现ã«èª¬æã§ããŸãã ãŠã£ã³ããŠä»æ§ïŒ WindowSpecificationãªããžã§ã¯ãïŒã¯ãå®éã®ãŠã£ã³ããŠãŸãã¯èŠçŽ ãæ€çŽ¢ããåºæºãä¿åããŸãã
詳现ãªãŠã£ã³ããŠä»æ§ã®äŸïŒ
>>> dlg_spec = app.window(title='Untitled - Notepad') >>> dlg_spec <pywinauto.application.WindowSpecification object at 0x0568B790> >>> dlg_spec.wrapper_object() <pywinauto.controls.win32_controls.DialogWrapper object at 0x05639B70>
ãŠã£ã³ããŠèªäœã¯ã .wrapper_object()
ã¡ãœãããåŒã³åºãããšã§æ€çŽ¢ãããŸãã å®éã®ãŠã£ã³ããŠ/èŠçŽ ã«å¯ŸããŠäžçš®ã®ãã©ãããŒããè¿ããã ElementNotFoundError
ã¹ããŒããŸãïŒè€æ°ã®èŠçŽ ãèŠã€ãã£ãå Žåãã€ãŸããæ€çŽ¢æ¡ä»¶ãçµã蟌ãå¿
èŠãããå Žåã¯ElementAmbiguousError
ã¹ããŒããŸãïŒã ãã®ãã©ãããŒãã¯ãèŠçŽ ã«å¯ŸããŠäœããã®ã¢ã¯ã·ã§ã³ãå®è¡ããæ¹æ³ããŸãã¯èŠçŽ ããããŒã¿ãååŸããæ¹æ³ããã§ã«ç¥ã£ãŠããŸãã
Pythonã¯.wrapper_object()
åŒã³åºããé衚瀺ã«ããŠãæçµã³ãŒããçãããããšãã§ããŸãã ãããã°ã®ã¿ã«äœ¿çšããããšããå§ãããŸãã æ¬¡ã®2è¡ã¯ãŸã£ããåãããšãè¡ããŸãã
dlg_spec.wrapper_object().minimize() # debugging dlg_spec.minimize() # production
ãŠã£ã³ããŠãæå®ããããã®å€ãã®æ€çŽ¢æ¡ä»¶ããããŸãã 以äžã«äŸã瀺ããŸãã
# app.window(title_re='.* - Notepad$').window(class_name='Edit') # ( AND) dlg = Desktop(backend="uia").Calculator dlg.window(auto_id='num8Button', control_type='Button')
å¯èœãªãã¹ãŠã®åºæºã®ãªã¹ãã¯ã pywinauto.findwindows.find_elementsïŒ...ïŒé¢æ°ã®ããã¯ã«ãããŸãã
屿§ããã³ããŒã¢ã¯ã»ã¹ããžãã¯
Pythonã䜿çšãããšããŠã£ã³ããŠã®ä»æ§ãç°¡åã«äœæã§ãããªããžã§ã¯ãã®å±æ§ãåçã«èªèã§ããŸãïŒ __getattribute__
ã¡ãœããã¯å
éšã§åå®çŸ©ãããŸãïŒã ãã¡ããã屿§ã®ååã«ã¯ã倿°ã®ååãšåãå¶éãé©çšãããŸãïŒã¹ããŒã¹ãã³ã³ãããŸãã¯ãã®ä»ã®ç¹æ®æåã¯æ¿å
¥ã§ããŸããïŒã 幞ããªããšã«ãpywinautoã¯ãããããããã¹ãããããæ€çŽ¢ã¢ã«ãŽãªãºã ã䜿çšããŸããããã¯ãã¿ã€ããã¹ãå°ããªå€åã«å¯ŸããŠå
ç¢ã§ãã
app.UntitledNotepad # , app.window(best_match='UntitledNotepad')
UnicodeæååïŒãã·ã¢èªãªã©ïŒãã¹ããŒã¹ãªã©ãåŒãç¶ãå¿ èŠãªå Žåã¯ãããŒã¢ã¯ã»ã¹ãå®è¡ã§ããŸãïŒéåžžã®èŸæžã®ããã«ïŒã
app['Untitled - Notepad'] # , app.window(best_match='Untitled - Notepad')
ããžãã¯ããŒã ã®5ã€ã®ã«ãŒã«
åç §ããžãã¯åãèŠã€ããæ¹æ³ã¯ïŒ æ€çŽ¢åã«ã¢ã€ãã ã«å²ãåœãŠããããã®ã æšæºã«éåžžã«é¡äŒŒããååãæå®ãããšãèŠçŽ ãèŠã€ãããŸãã
- ã¿ã€ãã«å¥ïŒããã¹ããååïŒïŒ
app.Properties.OK.click()
- ããã¹ãããã³èŠçŽ ã¿ã€ãå¥ïŒ
app.Properties.OKButton.click()
- ã¿ã€ããšçªå·å¥ïŒ
app.Properties.Button3.click()
ïŒååButton0
ãšButton1
æåã«èŠã€ãã£ãèŠçŽ ã«çµã³ä»ããããButton2
ã¯2çªç®ã«Button2
ãããé çªã«-ããã¯æŽå²çã«ïŒ - éçããã¹ãïŒå·ŠãŸãã¯äžïŒããã³ã¿ã€ãå¥ïŒ
app.OpenDialog.FileNameEdit.set_text("")
ïŒåçããã¹ããæã€èŠçŽ ã«æçšïŒ - ã¿ã€ãå¥ããã³ããã¹ãå
ïŒ
app.Properties.TabControlSharing.select("General")
éåžžã2ã€ãŸãã¯3ã€ã®ã«ãŒã«ãåæã«é©çšãããŸããããŸãã«é©çšãããŸãã åèŠçŽ ã§äœ¿çšå¯èœãªç¹å®ã®ååã確èªããã«ã¯ã print_control_identifiersïŒïŒã¡ãœããã䜿çšã§ããŸãã ç»é¢ãšãã¡ã€ã«ã®äž¡æ¹ã«èŠçŽ ã®ããªãŒãå°å·ã§ããŸãã åèŠçŽ ã«ã€ããŠããã®åç §ããžãã¯åãåºåãããŸãã ãããããåèŠçŽ ã®ãã詳现ãªä»æ§ã貌ãä»ããããšãã§ããŸãã ã¹ã¯ãªããã®çµæã¯æ¬¡ã®ããã«ãªããŸãã
app.Properties.child_window(title="Contains:", auto_id="13087", control_type="Edit")
>>> app.Properties.print_control_identifiers() Control Identifiers: Dialog - 'Windows NT Properties' (L688, T518, R1065, B1006) [u'Windows NT PropertiesDialog', u'Dialog', u'Windows NT Properties'] child_window(title="Windows NT Properties", control_type="Window") | | Image - '' (L717, T589, R749, B622) | [u'', u'0', u'Image1', u'Image0', 'Image', u'1'] | child_window(auto_id="13057", control_type="Image") | | Image - '' (L717, T630, R1035, B632) | ['Image2', u'2'] | child_window(auto_id="13095", control_type="Image") | | Edit - 'Folder name:' (L790, T596, R1036, B619) | [u'3', 'Edit', u'Edit1', u'Edit0'] | child_window(title="Folder name:", auto_id="13156", control_type="Edit") | | Static - 'Type:' (L717, T643, R780, B658) | [u'Type:Static', u'Static', u'Static1', u'Static0', u'Type:'] | child_window(title="Type:", auto_id="13080", control_type="Text") | | Edit - 'Type:' (L790, T643, R1036, B666) | [u'4', 'Edit2', u'Type:Edit'] | child_window(title="Type:", auto_id="13059", control_type="Edit") | | Static - 'Location:' (L717, T669, R780, B684) | [u'Location:Static', u'Location:', u'Static2'] | child_window(title="Location:", auto_id="13089", control_type="Text") | | Edit - 'Location:' (L790, T669, R1036, B692) | ['Edit3', u'Location:Edit', u'5'] | child_window(title="Location:", auto_id="13065", control_type="Edit") | | Static - 'Size:' (L717, T695, R780, B710) | [u'Size:Static', u'Size:', u'Static3'] | child_window(title="Size:", auto_id="13081", control_type="Text") | | Edit - 'Size:' (L790, T695, R1036, B718) | ['Edit4', u'6', u'Size:Edit'] | child_window(title="Size:", auto_id="13064", control_type="Edit") | | Static - 'Size on disk:' (L717, T721, R780, B736) | [u'Size on disk:', u'Size on disk:Static', u'Static4'] | child_window(title="Size on disk:", auto_id="13107", control_type="Text") | | Edit - 'Size on disk:' (L790, T721, R1036, B744) | ['Edit5', u'7', u'Size on disk:Edit'] | child_window(title="Size on disk:", auto_id="13106", control_type="Edit") | | Static - 'Contains:' (L717, T747, R780, B762) | [u'Contains:1', u'Contains:0', u'Contains:Static', u'Static5', u'Contains:'] | child_window(title="Contains:", auto_id="13088", control_type="Text") | | Edit - 'Contains:' (L790, T747, R1036, B770) | [u'8', 'Edit6', u'Contains:Edit'] | child_window(title="Contains:", auto_id="13087", control_type="Edit") | | Image - 'Contains:' (L717, T773, R1035, B775) | [u'Contains:Image', 'Image3', u'Contains:2'] | child_window(title="Contains:", auto_id="13096", control_type="Image") | | Static - 'Created:' (L717, T786, R780, B801) | [u'Created:', u'Created:Static', u'Static6', u'Created:1', u'Created:0'] | child_window(title="Created:", auto_id="13092", control_type="Text") | | Edit - 'Created:' (L790, T786, R1036, B809) | [u'Created:Edit', 'Edit7', u'9'] | child_window(title="Created:", auto_id="13072", control_type="Edit") | | Image - 'Created:' (L717, T812, R1035, B814) | [u'Created:Image', 'Image4', u'Created:2'] | child_window(title="Created:", auto_id="13097", control_type="Image") | | Static - 'Attributes:' (L717, T825, R780, B840) | [u'Attributes:Static', u'Static7', u'Attributes:'] | child_window(title="Attributes:", auto_id="13091", control_type="Text") | | CheckBox - 'Read-only (Only applies to files in folder)' (L790, T825, R1035, B841) | [u'CheckBox0', u'CheckBox1', 'CheckBox', u'Read-only (Only applies to files in folder)CheckBox', u'Read-only (Only applies to files in folder)'] | child_window(title="Read-only (Only applies to files in folder)", auto_id="13075", control_type="CheckBox") | | CheckBox - 'Hidden' (L790, T848, R865, B864) | ['CheckBox2', u'HiddenCheckBox', u'Hidden'] | child_window(title="Hidden", auto_id="13076", control_type="CheckBox") | | Button - 'Advanced...' (L930, T845, R1035, B868) | [u'Advanced...', u'Advanced...Button', 'Button', u'Button1', u'Button0'] | child_window(title="Advanced...", auto_id="13154", control_type="Button") | | Button - 'OK' (L814, T968, R889, B991) | ['Button2', u'OK', u'OKButton'] | child_window(title="OK", auto_id="1", control_type="Button") | | Button - 'Cancel' (L895, T968, R970, B991) | ['Button3', u'CancelButton', u'Cancel'] | child_window(title="Cancel", auto_id="2", control_type="Button") | | Button - 'Apply' (L976, T968, R1051, B991) | ['Button4', u'ApplyButton', u'Apply'] | child_window(title="Apply", auto_id="12321", control_type="Button") | | TabControl - '' (L702, T556, R1051, B962) | [u'10', u'TabControlSharing', u'TabControlPrevious Versions', u'TabControlSecurity', u'TabControl', u'TabControlCustomize'] | child_window(auto_id="12320", control_type="Tab") | | | | TabItem - 'General' (L704, T558, R753, B576) | | [u'GeneralTabItem', 'TabItem', u'General', u'TabItem0', u'TabItem1'] | | child_window(title="General", control_type="TabItem") | | | | TabItem - 'Sharing' (L753, T558, R801, B576) | | [u'Sharing', u'SharingTabItem', 'TabItem2'] | | child_window(title="Sharing", control_type="TabItem") | | | | TabItem - 'Security' (L801, T558, R851, B576) | | [u'Security', 'TabItem3', u'SecurityTabItem'] | | child_window(title="Security", control_type="TabItem") | | | | TabItem - 'Previous Versions' (L851, T558, R947, B576) | | [u'Previous VersionsTabItem', u'Previous Versions', 'TabItem4'] | | child_window(title="Previous Versions", control_type="TabItem") | | | | TabItem - 'Customize' (L947, T558, R1007, B576) | | [u'CustomizeTabItem', 'TabItem5', u'Customize'] | | child_window(title="Customize", control_type="TabItem") | | TitleBar - 'None' (L712, T521, R1057, B549) | ['TitleBar', u'11'] | | | | Menu - 'System' (L696, T526, R718, B548) | | [u'System0', u'System', u'System1', u'Menu', u'SystemMenu'] | | child_window(title="System", auto_id="MenuBar", control_type="MenuBar") | | | | | | MenuItem - 'System' (L696, T526, R718, B548) | | | [u'System2', u'MenuItem', u'SystemMenuItem'] | | | child_window(title="System", control_type="MenuItem") | | | | Button - 'Close' (L1024, T519, R1058, B549) | | [u'CloseButton', u'Close', 'Button5'] | | child_window(title="Close", control_type="Button")
å Žåã«ãã£ãŠã¯ãããªãŒå
šäœã®å°å·ãé
ããªãå ŽåããããŸãïŒããšãã°ãiTunesã§ã¯1ã€ã®ã¿ãã«æ¢ã«3000åã®èŠçŽ ããããŸãïŒïŒããããdepth
ãã©ã¡ãŒã¿ãŒã䜿çšã§ããŸãïŒ depth=1
èŠçŽ èªäœã depth=2
çŽæ¥ã®åã®ã¿ãªã©ã child_window
äœæãããšãã«ä»æ§ã§æå®ããããšãã§ããŸãã
äŸ
ãªããžããªå ã®ãµã³ãã«ã®ãªã¹ããåžžã«æŽæ°ããŠããŸã ã æè¿ã®ãã®ã®ãã¡ãWireSharkãããã¯ãŒã¯ã¢ãã©ã€ã¶ãŒã®èªååã«æ³šç®ãã䟡å€ããããŸãïŒããã¯Qt5ã¢ããªã±ãŒã·ã§ã³ã®è¯ãäŸã§ãããã ããscapyãããããããã®ã¿ã¹ã¯ã¯GUIãªãã§è§£æ±ºã§ããŸããPythonããã±ãŒãžscapyã®ã¹ããã¡ãŒã§ã ïŒã ãªãã³ããŒã«ããŒã䜿çšããMSãã€ã³ããªãŒãã¡ãŒã·ã§ã³ã®äŸããããŸãã
ç§ã®åŠçã«ãã£ãŠæžãããå¥ã®åªããäŸïŒ ãã¡ã€ã«ãexplorer.exeããGoogleãã©ã€ãã®ChromeããŒãžã«ãã©ãã°ã¢ã³ãããããããŸã ïŒå°ãåŸã§ã¡ã€ã³ãªããžããªã«è»¢éãããŸãïŒã
ãããŠããã¡ãããããŒããŒãã€ãã³ãïŒãããããŒïŒãšããŠã¹ããµãã¹ã¯ã©ã€ãããäŸïŒ
hook_and_listen.py
è¬èŸ
ãããžã§ã¯ãã®éçºãçµ¶ããæ¯æŽããŠãããŠãã人ã
ã«æè¬ããŸãã ç§ãšãã¬ã³ã¿ã€ã³ã«ãšã£ãŠãããã¯åžžã«è¶£å³ã§ãã UNNããã®ç§ã®åŠçã®ãã¡ã®2äººã¯æè¿ããã®äž»é¡ã«é¢ããŠåŠå£«å·ãæè·ããŸããã Alexanderã¯MS UIãªãŒãã¡ãŒã·ã§ã³ã®ãµããŒãã«å€å€§ãªè²¢ç®ãããæè¿ã§ã¯ããã¹ãããããã£ïŒãããæãé£ããæ©èœã§ãïŒã«åºã¥ããèšé²åçãåçã«åºã¥ããèªåã³ãŒããžã§ãã¬ãŒã¿ãŒã®äœæãéå§ããŸããã Linux AT-SPI ( mouse
keyboard
python-xlib â 0.6.x).
Python, - , . - . . (QuantifiedCode, Codacy Landscape) ( AppVeyor) 95%.
, , !
远å ã®ãªãœãŒã¹
StackOverflow ( SO ) . Gitter' .
open-source GUI . Autohotkey ( ) PyAutoGUI ( Al Sweigart: "Automate the Boring Stuff with Python" ).