Pythonã©ã€ãã©ãª â ã¯ãWindows äžã®ãã¹ã¯ããã GUI ã¢ããªã±ãŒã·ã§ã³ãèªååããããã®ãªãŒãã³ ãœãŒã¹ ãããžã§ã¯ãã§ããéå» 2 幎éã§ã次ã®ãããªæ°ããäž»èŠæ©èœã远å ãããŸããã
- MS UI ãªãŒãã¡ãŒã·ã§ã³ ãã¯ãããžã®ãµããŒããã€ã³ã¿ãŒãã§ãŒã¹ã¯åãã§ãããWinFormsãWPFãQt5ãWindows ã¹ã㢠(UWP) ãªã©ãWindows äžã®ã»ãŒãã¹ãŠã®ãã®ããµããŒããããããã«ãªããŸããã
- ããã¯ãšã³ã/ãã©ã°ã€ã³ã·ã¹ãã ïŒçŸåšãå
éšã«ã¯2ã€ã®ã·ã¹ãã ããããŸãïŒããã©ã«ã
"win32"ОМПвÑй"uia"ïŒã次ã«ãã¯ãã¹ãã©ãããã©ãŒã ã«åããŠé 調ã«é²ãã§ããŸãã - ããŠã¹ãšããŒããŒãçšã® Win32 ãã㯠(pyHook ã®ç²Ÿç¥ã«åºã¥ãããã ããŒ)ã
ãŸãããã¹ã¯ãããèªååçšã®ãªãŒãã³ ãœãŒã¹ã§äœãå©çšã§ãããã«ã€ããŠãç°¡åã«ã¬ãã¥ãŒããŸã (æ¬æ Œçãªæ¯èŒã䞻匵ãããã®ã§ã¯ãããŸãã)ã
ãã®èšäºã¯ããã³ã¹ã¯ã§éå¬ãããSQA Days 20ã«ã³ãã¡ã¬ã³ã¹ã®ã¬ããŒãã®äžéšã§ãïŒ Ðž ïŒãäžéšãã·ã¢èªç pywinauto çšã
- äž»ãªåãçµã¿
- åºæ¬çãªãã¹ã¯ãããã¢ã¯ã»ã·ããªãã£æè¡
ãŸãããã®åéã«ããããªãŒãã³ãœãŒã¹ã®æŠèŠãç°¡åã«èª¬æããŸãããããã¹ã¯ããã GUI ã¢ããªã±ãŒã·ã§ã³ã®å ŽåãSelenium ã䜿çšãã Web ã®å Žåãããç¶æ³ãå°ãè€éã«ãªããŸããäž»ãªã¢ãããŒãã¯æ¬¡ã®ãšããã§ãã
åº§æšæ³
ã¯ãªãã¯ãã€ã³ããããŒãã³ãŒãããŠãããããæåããããšãæåŸ
ããŸãã
[+] ã¯ãã¹ãã©ãããã©ãŒã ã§å®è£
ãç°¡åã
[+] ãã¹ãã®ãèšé²åçãèšé²ãç°¡åã«äœæã§ããŸãã
[-] ç»é¢è§£å床ãããŒãããã©ã³ãããŠã£ã³ããŠãµã€ãºãªã©ã®å€æŽã«å¯ŸããŠæãäžå®å®ã§ãã
[-] å€å€§ãªãµããŒãäœæ¥ãå¿
èŠã§ããããã¹ããæåããåçæããããæåã§ãã¹ãããæ¹ãç°¡åãªå ŽåããããããŸãã
[-] ã¢ã¯ã·ã§ã³ã®ã¿ãèªååããŸããæ€èšŒãšããŒã¿æœåºã«ã¯ä»ã®æ¹æ³ããããŸãã
ããŒã«ïŒã¯ãã¹ãã©ãããã©ãŒã ïŒïŒ , , ãã®ä»å€æ°ãéåžžãããè€éãªããŒã«ã«ã¯ãã®æ©èœãå«ãŸããŠããŸã (å¿ ãããã¯ãã¹ãã©ãããã©ãŒã ã§ã¯ãããŸãã)ã
åº§æšæ³ã¯ä»ã®ã¢ãããŒããè£å®ã§ãããšããããšã¯èšããŸã§ããããŸãããããšãã°ãã«ã¹ã¿ã ã°ã©ãã£ãã¯ã®å Žåãçžå¯Ÿåº§æš (ç»é¢å šäœã§ã¯ãªãããŠã£ã³ããŠ/èŠçŽ ã®å·Šäžé ãã) ãã¯ãªãã¯ã§ããŸããããã¯éåžžãç¹ã«èŠçŽ å šäœã®é·ã/å¹ ãèæ ®ãããšéåžžã«ä¿¡é Œæ§ãé«ããªããŸã (ç»é¢è§£å床ãç°ãªã£ãŠãåé¡ã¯ãããŸãã)ã
å¥ã®ãªãã·ã§ã³: ãã¹ãçšã«å®å®ããèšå®ã®ãã·ã³ã 1 å°ã ãå²ãåœãŠã (ã¯ãã¹ãã©ãããã©ãŒã ã§ã¯ãããŸããããå Žåã«ãã£ãŠã¯é©ããŠããŸã)ã
åç §ç»åã®èªè
[+] ã¯ãã¹ãã©ãããã©ãŒã[+-] æ¯èŒçä¿¡é Œæ§ãé«ãïŒåº§æšæ¹åŒãããåªããŠããïŒããããã§ãããªãã¯ãå¿ èŠã§ãã
[-+] èªèã¢ã«ãŽãªãºã ã«CPUãªãœãŒã¹ãå¿ èŠãªãããæ¯èŒçäœéã§ãã
[-] ååãšããŠããã¹ãèªèïŒOCRïŒã®è©±ã¯åºãŸãã => ããã¹ãããŒã¿ãååŸããããšã¯äžå¯èœã§ããç§ã®ç¥ãéããæ¢åã® OCR ãœãªã¥ãŒã·ã§ã³ã¯ãã®çš®ã®ã¿ã¹ã¯ã«ã¯ããŸãä¿¡é Œæ§ãé«ããªããåºã䜿çšãããŠããŸãã (ãŸã ããã§ãªãå Žåã¯ã³ã¡ã³ãããåŸ ã¡ããŠããŸã)ã
ããŒã«ïŒ , (Sikuli äºæãçŽç²ãª Python)ã .
ã¢ã¯ã»ã·ããªãã£æè¡
[+] ã·ã¹ãã ããã¬ãŒã ã¯ãŒã¯ã«ãã£ãŠã©ã®ããã«ã¬ã³ããªã³ã°ããããã«é¢ä¿ãªããããã¹ãã§æ€çŽ¢ã§ãããããæãä¿¡é Œæ§ã®é«ãæ¹æ³ã§ãã[+] ããã¹ã ããŒã¿ãæœåºã§ããããããã¹ãçµæã®æ€èšŒã容æã«ãªããŸãã
[+] CPU ãªãœãŒã¹ãã»ãšãã©æ¶è²»ããªããããéåžžã¯æãé«éã§ãã
[-] ã¯ãã¹ãã©ãããã©ãŒã ããŒã«ãäœæããã®ã¯å°é£ã§ãããã¹ãŠã®ãªãŒãã³ ãœãŒã¹ ã©ã€ãã©ãªã¯ã1 ã€ãŸã㯠2 ã€ã®ã¢ã¯ã»ã·ããªã㣠ãã¯ãããžããµããŒãããŠããŸãã Windows/Linux/MacOS ã¯ãTestCompleteãUFTãSquish ãªã©ã®ææã®ãã®ä»¥å€ã§ã¯å®å šã«ãµããŒããããŠããŸããã
[-] ãã®æè¡ã¯åççã«åžžã«å©çšã§ãããšã¯éããŸãããããšãã°ãVirtualBox å ã®èµ·åç»é¢ããã¹ãããå Žåãç»åèªèãªãã§ã¯å®è¡ã§ããŸãããããããå€ãã®å žåçãªã±ãŒã¹ã§ã¯ãã¢ã¯ã»ã·ããªãã£ã®ã¢ãããŒãã¯äŸç¶ãšããŠé©çšå¯èœã§ããããã«ã€ããŠã¯ãä»åŸããã«ã話ãããŸãã
ããŒã«ïŒ C#ã§ã¯ã C#ïŒSeleniumäºæïŒã®å Žåã C#ïŒAppiumäºæïŒã®å Žåã , ïŒLDTPäºæïŒã , ã«ããŒã§ã¯ã (Linuxãã¹ã¯ããããã¹ããããžã§ã¯ã)ãšãã®WindowsããŒãžã§ã³ .
LDTP ã¯ãããããã¢ã¯ã»ã·ããªãã£æè¡ã«åºã¥ããå¯äžã®ã¯ãã¹ãã©ãããã©ãŒã ã®ãªãŒãã³ãœãŒã¹ ããŒã« (ãŸãã¯ã©ã€ãã©ãª ãã¡ããª) ã§ããããããããŸã人æ°ããããŸãããç§èªèº«ã¯ãŸã 䜿çšããŠããŸããããã¬ãã¥ãŒã«ãããšããã®ã€ã³ã¿ãŒãã§ãŒã¹ã¯ããŸã䟿å©ã§ã¯ãªãããã§ããè¯å®çãªã¬ãã¥ãŒãããã°ãã³ã¡ã³ãæ¬ã§å ±æããŠãã ããã
ãã¹ãããã¯ãã¢ïŒå¥åã€ã³ãã¢ãã€ã¯ïŒ
ã¯ãã¹ãã©ãããã©ãŒã ã¢ããªã±ãŒã·ã§ã³ã®å Žåãéçºè èªèº«ããã¹ãå¯èœæ§ã確ä¿ããããã®å éšã¡ã«ããºã ãäœæããããšããããããŸããããšãã°ãã¢ããªã±ãŒã·ã§ã³å ã«ãµãŒãã¹ TCP ãµãŒããŒãäœæãããã¹ãã§ãã®ãµãŒããŒã«æ¥ç¶ããŠãäœãã¯ãªãã¯ããããã©ãããããŒã¿ãååŸããããªã©ã®ããã¹ã ã³ãã³ããéä¿¡ããŸããä¿¡é Œæ§ã¯é«ãã§ãããæ±çšçã§ã¯ãããŸããã
åºæ¬çãªãã¹ã¯ãããã¢ã¯ã»ã·ããªãã£æè¡
å€ãè¯ãWin32 API
WPF ããã³ Windows ã¹ãã¢ä»¥åã«äœæãããã»ãšãã©ã® Windows ã¢ããªã±ãŒã·ã§ã³ã¯ãäœããã®åœ¢ã§ Win32 API äžã«æ§ç¯ãããŠããŸãããã€ãŸããMFCãWTLãC++ BuilderãDelphiãVB6 ãªã©ãããããã¹ãŠã®ããŒã«ã¯ Win32 API ã䜿çšããŸãã Windows ãã©ãŒã ã§ããWin32 API ãšã»ãŒäºææ§ããããŸãã
ããŒã«ïŒ (VBã«äŒŒãŠãã) ããã³ Python ã©ãã㌠, ïŒç¬èªã®èšèªãIDispatch COMã€ã³ã¿ãŒãã§ãŒã¹ããããŸãïŒã (ãã€ãœã³) ïŒã«ããŒïŒã ïŒã«ããŒïŒã
Microsoft UI ãªãŒãã¡ãŒã·ã§ã³
äž»ãªå©ç¹: MS UI Automation ãã¯ãããžãŒã¯ããŸããªäŸå€ãé€ããŠãWindows äžã® GUI ã¢ããªã±ãŒã·ã§ã³ã®å€§éšåããµããŒãããŸããåé¡: Win32 API ãããåŠç¿ãããã»ã©ç°¡åã§ã¯ãããŸãããããã§ãªããã°ã誰ããããã©ããããªãã§ãããã
å®éãããã¯ã«ã¹ã¿ã COMã€ã³ã¿ãŒãã§ãŒã¹ã®ã»ããã§ãïŒäž»ã«ã UIAutomationCore.dllïŒãããã.NETã·ã§ã«ãåããŠããŸãã namespace System.Windows.Automationãã¡ãªã¿ã«ããã°ãå°å
¥ãããŠãããäžéšã® UI èŠçŽ ãã¹ããããããå¯èœæ§ããããŸãããããã£ãŠãUIAutomationCore.dll ãçŽæ¥äœ¿çšããããšããå§ãããŸã (C# ã® UiaComWrapper ã«ã€ããŠèããããšãããå Žåã¯ããããããã§ã)ã
COM ã€ã³ã¿ãŒãã§ã€ã¹ã®çš®é¡:
ïŒïŒïŒåºæ¬çãªããšã¯ã諞æªã®æ ¹æºããšããŠç¥ãããŠããŸããæäœã¬ãã«ã§ããŸã£ãããŠãŒã¶ãŒãã¬ã³ããªãŒã§ã¯ãããŸããã
ïŒïŒïŒIDispatchåã³ãã®æŽŸçååïŒäŸïŒ Excel.Application) ã¯ãwin32com.client ããã±ãŒãž (pyWin32 ã®äžéš) ã䜿çšã㊠Python ã§äœ¿çšã§ããŸããæã䟿å©ã§çŸãããªãã·ã§ã³ã
ïŒïŒïŒãµãŒãããŒãã£ã®Pythonããã±ãŒãžã䜿çšã§ããã«ã¹ã¿ã ã€ã³ã¿ãŒãã§ãŒã¹ .
ããŒã«ïŒ C#ã§ã¯ã 0.6.0 +ã C#ã§ã¯ã (UIAutomationCore.dll äžã® C ã©ãããŒã®ãœãŒã¹ ã³ãŒãã¯å ¬éãããŠããŸãã) Ruby ã§ã
AT-SPI
ã»ãŒãã¹ãŠã® Linux ãã¡ããªãŒã®è»žã¯ X Window System äžã«æ§ç¯ãããŠããŸãã (Fedora 25 ã§ã¯ããXã㯠Wayland ã«å€æŽãããŸãã)ããXãã§ã¯ãããã¬ãã«ã®ãŠã£ã³ããŠãšããŠã¹/ããŒããŒãã®ã¿ãæäœã§ããŸãããã¿ã³ããªã¹ã ããã¯ã¹ãªã©ã®è©³çްãªåæã«ã¯ãAT-SPI ãã¯ãããžããããŸããæãäžè¬çãªãŠã£ã³ã㊠ãããŒãžã£ãŒã«ã¯ãã¢ããªã±ãŒã·ã§ã³ã«èªååããã GUI ãæäŸããããããã AT-SPI ã¬ãžã¹ã㪠ããŒã¢ã³ããããŸã (å°ãªããšã Qt ãš GTK ã¯ãµããŒããããŠããŸã)ã
ããŒã«ïŒ .
ç§ã®æèŠã§ã¯ãpyatspi2 ã«ã¯åã PyGObject ã®ãããªäŸåé¢ä¿ãå€ãããŸãããã¯ãããžãŒèªäœã¯ãéåžžã®åçã©ã€ãã©ãªãšããŠå©çšã§ããŸãã libatspi.soãä»å± ã pywinauto ã©ã€ãã©ãªã«ã€ããŠã¯ãlibatspi.so ãš ctypes ã¢ãžã¥ãŒã«ãããŒãããããšã«ãã£ãŠãAT-SPI ãµããŒããå®è£
ããäºå®ã§ãã GTK+ ãš Qt ã¢ããªã±ãŒã·ã§ã³ã§ã¯è¥å¹²ç°ãªããããæ£ããããŒãžã§ã³ã䜿çšããããšã«ã¯å°ããªåé¡ãããããŸãããå®å
šãª Linux ãµããŒããåãã pywinauto 0.7.0 ã®ãªãªãŒã¹ã¯ã2018 幎ååã«äºå®ãããŠããŸãã
Apple ã¢ã¯ã»ã·ããªã㣠API
MacOS ã«ã¯ç¬èªã®èªååèšèªã§ãã AppleScript ããããŸãã Python ã§åæ§ã®ãã®ãå®è£ ããã«ã¯ããã¡ãã ObjectiveC ã®é¢æ°ã䜿çšããå¿ èŠããããŸãã MacOS 10.6 以éã§ã¯ãpyobjc ããã±ãŒãžãããªã€ã³ã¹ããŒã«ããã Python ã«å«ãŸããŠããããã§ããããã«ãããå°æ¥ã® pywinauto ãµããŒãã®ããã«äŸåé¢ä¿ãªã¹ããç¶æãããããªããŸãã
ããŒã«ïŒApple Scriptèšèªã«å ããŠã泚ç®ã«å€ããã®ã¯ ãå¥å pyatomã LDTP ãšã€ã³ã¿ãŒãã§ãŒã¹äºææ§ããããŸãããã¹ã¿ã³ãã¢ãã³ ã©ã€ãã©ãªã§ããããŸããèŒã£ãŠãã ç§ã®çåŸãæžãããã®ã§ããæ¢ç¥ã®åé¡ããããŸã: æè»ãªã¿ã€ãã³ã° (æ¹æ³) ãæ©èœããªã waitFor*ïŒãããããå
šäœçã«ã¯æªãããšã§ã¯ãããŸããã
pywinauto ã®äœ¿ãæ¹
æåã«ãã¹ãããšã¯ãGUI ãªããžã§ã¯ã ã€ã³ã¹ãã¯ã¿ãŒ (ããããã¹ã〠ããŒã«) ãè£ åããããšã§ããããã¯ãèŠçŽ ã®éå±€ãã©ã®ããã«æ§é åãããŠããããã©ã®ãããªããããã£ãå©çšå¯èœããªã©ãã¢ããªã±ãŒã·ã§ã³ãå éšããç ç©¶ããã®ã«åœ¹ç«ã¡ãŸããæãæåãªç©äœæ€æ»å®:
- ã¹ãã€++ â Express ãŸã㯠Community Edition ãå«ã Visual Studio ã«å«ãŸããŠããŸãã Win32 API ã䜿çšããŸãã圌ã®ã¯ããŒã³ãç¥ãããŠãã AutoIt ãŠã£ã³ããŠæ å ±.
- Inspect.exe â Windows SDK ã«å«ãŸããŠããŸããã€ã³ã¹ããŒã«ããŠããå Žåã¯ã64ãããWindowsã§ã¯æ¬¡ã®ãã©ã«ãã«ãããŸãã
C:Program Files (x86)Windows Kits<winver>binx64ãã€ã³ã¹ãã¯ã¿èªäœã§ã¯ã¢ãŒããéžæããå¿ èŠããããŸã UIãªãŒãã¡ãŒã·ã§ã³ MS AA (Active AccessibilityãUI Automation ã®ç¥å ) ã®ä»£ããã«ã
ã¢ããªã±ãŒã·ã§ã³ã確èªããåŸã䜿çšããããã¯ãšã³ããéžæããŸãã Application ãªããžã§ã¯ããäœæãããšãã«ããã¯ãšã³ãåãæå®ããã ãã§ååã§ãã
- ããã¯ãšã³ã=»win32â³ - çŸåšããã©ã«ãã§äœ¿çšãããŠãããMFCãWTLãVB6ãããã³ãã®ä»ã®ã¬ã¬ã·ãŒ ã¢ããªã±ãŒã·ã§ã³ã§é©åã«åäœããŸãã
- ããã¯ãšã³ã=»uia» â MS UI ãªãŒãã¡ãŒã·ã§ã³çšã®æ°ããããã¯ãšã³ã: WPF ããã³ WinForms ãšå®å
šã«é£æºããŸãã Delphi ããã³ Windows ã¹ã㢠ã¢ããªã«ãé©ããŠããŸãã Qt5 ããã³äžéšã® Java ã¢ããªã±ãŒã·ã§ã³ã§åäœããŸããäžè¬ã«ãInspect.exe ãèŠçŽ ãšãã®ããããã£ãèªèããå Žåããã®ããã¯ãšã³ãã¯é©ããŠããŸããååãšããŠãã»ãšãã©ã®ãã©ãŠã¶ã¯ UI ãªãŒãã¡ãŒã·ã§ã³ããµããŒãããŠããŸã (Mozilla ã¯ããã©ã«ãã§ãChrome ã¯èµ·åæã«ã³ãã³ãã©ã€ã³ ããŒãå
¥åããå¿
èŠããããŸã)
--force-renderer-accessibilityãInspect.exe ã®ããŒãžäžã®èŠçŽ ã確èªããŸãããã¡ããããã®åéã§ Selenium ãšç«¶äºããããšã¯ã»ãšãã©äžå¯èœã§ãããã©ãŠã¶ãæäœããããã®å¥ã®æ¹æ³ã§ã (ã¯ãã¹ãããã¯ãã®ã·ããªãªã«åœ¹ç«ã€å¯èœæ§ããããŸã)ã
èªååã®ãšã³ããªãŒãã€ã³ã
ã¢ããªã±ãŒã·ã§ã³ã¯ååã«ç ç©¶ãããŠããŸããã¢ããªã±ãŒã·ã§ã³ ãªããžã§ã¯ããäœæããŠèµ·åãããããã§ã«å®è¡äžã®ãªããžã§ã¯ãã«ã¢ã¿ããããŸããããã¯æšæºã¯ã©ã¹ã®åãªãã¯ããŒã³ã§ã¯ãããŸãã 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ïŒãã€ãŸããç®çèªããªããã° 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 ã€ã³ã¿ãŒãã§ãŒã¹ãæ§ç¯ãããåºæ¬çãªæŠå¿µã§ãããŠã£ã³ããŠ/èŠçŽ ããŸã ååšããŠããªããããã§ã«éããããŠããå Žåã§ãããããããŸãã¯ãã詳现ã«èšè¿°ã§ããŸãããŠã£ã³ããŠä»æ§ïŒãªããžã§ã¯ã ãŠã£ã³ããŠä»æ§) ã«ã¯ãå®éã®ãŠã£ã³ããŠãŸãã¯èŠçŽ ãæ€çŽ¢ããããã®åºæºãæ ŒçŽãããŸãã
詳现ãªãŠã£ã³ããŠä»æ§ã®äŸ:
>>> 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')å¯èœãªãã¹ãŠã®åºæºã®ãªã¹ãã¯é¢æ°ã®ããã¥ã¡ã³ãã«ãããŸãã .
屿§ãšããŒã«ããã¢ã¯ã»ã¹ã®éæ³
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çªç®ããããŠé çªã« â ãããæŽå²çã«èµ·ãã£ãããšã§ãïŒ - éçããã¹ãïŒå·ŠãŸãã¯äžïŒããã³ã¿ã€ãå¥:
app.OpenDialog.FileNameEdit.set_text("")(åçããã¹ããå«ãèŠçŽ ã«äŸ¿å©ã§ã) - ã¿ã€ãå¥ããã³å
éšã®ããã¹ãå¥:
app.Properties.TabControlSharing.select("General")
éåžžã2 ã€ãŸã㯠3 ã€ã®ã«ãŒã«ãåæã«é©çšãããŸããããã以äžé©çšãããããšã¯ãŸãã§ããåèŠçŽ ã«ã©ã®ãããªååãããã®ãââã確èªããã«ã¯ã次ã®ã¡ãœããã䜿çšããŸãã print_control_identifiers()ãèŠçŽ ã®ããªãŒãç»é¢ãšãã¡ã€ã«ã®äž¡æ¹ã«å°å·ã§ããŸããåèŠçŽ ããšã«ããã®åç §éæ³ã®ååãå°å·ãããŸããããããåèŠçŽ ã®ãã詳现ãªä»æ§ãã³ããŒããŠè²Œãä»ããããšãã§ããŸããã¹ã¯ãªããã®çµæã¯æ¬¡ã®ããã«ãªããŸãã
app.Properties.child_window(data-gt-translate-attributes='["title"]' 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(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")å Žåã«ãã£ãŠã¯ãããªãŒå
šäœãå°å·ãããšé
ããªãããšããããŸãïŒããšãã°ãiTunesã§ã¯1ã€ã®ã¿ãã«3000ãã®èŠçŽ ããããŸãïŒïŒãããã©ã¡ãŒã¿ã䜿çšã㊠depth ïŒæ·±ãïŒïŒ depth=1 â èŠçŽ èªäœã depth=2 - çŽç³»ã®åäŸã®ã¿ããªã©ãäœææã«ä»æ§æžã«æå®ããããšãã§ããŸã child_window.
äŸ
åžžã«è£å
ããŠããŸã ãææ°ã®ãã®ã®äžã§ã¯ãWireSharkãããã¯ãŒã¯ã¢ãã©ã€ã¶ãŒã®èªååãæ³šç®ã«å€ããŸãïŒããã¯Qt5ã¢ããªã±ãŒã·ã§ã³ã®è¯ãäŸã§ãããã ãããã®ã¿ã¹ã¯ã¯GUIããªããŠã解決ã§ããŸãã scapy.Sniffer Pythonããã±ãŒãžãã ïŒããªãã³ ããŒã«ããŒã䜿çšãã MS ãã€ã³ãã®èªååã®äŸããããŸãã
ç§ã®çåŸãæžããããäžã€ã®çŽ æŽãããäŸ: (å°ãåŸã§ã¡ã€ã³ãªããžããªã«ç§»è¡ããŸã)ã
ãããŠãã¡ãããããŒããŒã (ãããããŒ) ãšããŠã¹ ã€ãã³ãããµãã¹ã¯ã©ã€ãããäŸ:
.
æè¬
ãããžã§ã¯ãã®éçºã«åžžã«ååããŠãã ãã£ãŠããæ¹ã
ã«ç¹ã«æè¬ããŸããç§ã«ãšã£ãŠããã㊠ããã¯æ°žé ã®è¶£å³ã§ããæè¿ãUNN ã®ç§ã®åŠç 2 人ããã®ããŒãã§åŠå£«è«æãçºè¡šããŸããã MS UI Automation ã®ãµããŒãã«å€§ããè²¢ç®ããæè¿ã§ã¯ããã¹ã ããããã£ã«åºã¥ããèšé²åçãååã«åºã¥ãèªåã³ãŒã ãžã§ãã¬ãŒã¿ãŒã®äœæãéå§ããŸãã (ãããæãè€éãªæ©èœã§ã)ããããŸã§ã®ãšããã察象ã¯ãuiaãããã¯ãšã³ãã®ã¿ã§ãã AT-SPIïŒã¢ãžã¥ãŒã«ïŒãããŒã¹ã«ããæ°ããLinuxããã¯ãšã³ããéçº mouse О keyboard ã«åºã¥ã㊠(ãªãªãŒã¹ 0.6.x ã§ã¯ãã§ã«å®è£
ãããŠããŸã)ã
ç§ã¯ããªãé·ãéãPython ã§ã®èªååã«é¢ããç¹å¥ã³ãŒã¹ãæããŠããã®ã§ã修士課çšã®åŠçã®äžã«ã¯ãå°ããªæ©èœãèªååã®äŸãå®è£ ãã宿é¡ããã人ãããŸããç 究段éã®éèŠãªäºæãããã€ãŠã¯åŠçãã¡ã«ãã£ãŠçºæããããã®ã§ããããã ããã³ãŒãã®å質ãå³å¯ã«ç£èŠããå¿ èŠãããå ŽåããããŸãããã®ç¹ã§ã¯ãã³ãŒã ã«ãã¬ããžãçŽ 95% ã®éçã¢ãã©ã€ã¶ãŒ (QuantifiedCodeãCodacyãLandscape) ãšã¯ã©ãŠãå ã®èªåãã¹ã (AppVeyor ãµãŒãã¹) ãéåžžã«åœ¹ç«ã¡ãŸãã
ãŸããã¬ãã¥ãŒãæ®ãããããã°ãå ±åãããããã«ãªã¯ãšã¹ããéä¿¡ãããããŠãã ãã£ãçæ§ã«ãæè¬ããããŸãã
远å ãªãœãŒã¹
ç§ãã¡ã¯åé¡ãç£èŠããŠããŸã ïŒæè¿ç»å Žãã ïŒãããŠã ã ãããŸã .
æ¯ææŽæ°ããŸã ã GitHub ã®ã¹ã¿ãŒã®æ°ã§èšãã°ãAutohotkey (éåžžã«å€§ããªã³ãã¥ããã£ãšé·ãæŽå²ãæã€) ãš PyAutoGUI (äž»ã«èè Al Sweigart ã®æžç±ãAutomate the Boring Stuff with Pythonããªã©ã®äººæ°ã«ãã) ã®ã¿ããããéãæé·ããŠããŸãã
åºæïŒ habr.com
