æ¥ã ã®PCäœæ¥ãç¹ã«å®åçãªWindowsã¢ããªã±ãŒã·ã§ã³ã®æäœã«ããããããŠããŸãããïŒð€ ããã®äœæ¥ãèªååã§ããããªãâŠããšèããããšãããæ¹ãå€ãã¯ãããããªé¡ããå¶ããŠãããã®ããPythonã©ã€ãã©ãªã® pywinauto ã§ãïŒ
pywinauto ã¯ãPython ã¹ã¯ãªããã䜿ã£ãŠ Windows ã® GUI (ã°ã©ãã£ã«ã«ãŠãŒã¶ãŒã€ã³ã¿ãŒãã§ãŒã¹) ãèªåæäœããããã®åŒ·åãªããŒã«ãããã§ããããŠã¹ã®ã¯ãªãã¯ãããŒããŒãå ¥åããŠã£ã³ããŠã®å¶åŸ¡ãªã©ãããã°ã©ã ããå®è¡ã§ãããããæ¥åã®å¹çåããœãããŠã§ã¢ãã¹ãã®èªååãRPA (Robotic Process Automation) ã®æ§ç¯ãªã©ãå¹ åºãçšéã§æŽ»çšãããŠããŸãã
ãã®èšäºã§ã¯ãpywinauto ã®åºæ¬çãªæŠå¿µããå ·äœçãªäœ¿ãæ¹ãããã«ã¯å¿çšãã¯ããã¯ãŸã§ã詳现ã«è§£èª¬ããŠãããŸãããã®èšäºãèªãã°ãããªãã pywinauto ã䜿ã£ãŠ Windows æäœã®èªååãå§ããããããã«ãªãã§ãããïŒðª
ð¡ pywinauto ãšã¯ïŒ ãã®ç¹åŸŽãšã¡ãªãã
pywinauto ã¯ãMicrosoft Windows ã® GUI ãèªååããããã«éçºããã Python ã¢ãžã¥ãŒã«ã®ã»ããã§ãããã®äž»ãªç¹åŸŽãšã¡ãªãããèŠãŠãããŸãããã
- Python ã«ããå¶åŸ¡: èªã¿ãããæžãããã Python èšèªã§ GUI æäœãèšè¿°ã§ããŸããããã°ã©ãã³ã°çµéšãããã°æ¯èŒç容æã«ç¿åŸã§ããè€éãªããžãã¯ãå®è£ ããããã®ãç¹åŸŽã§ãã
- ãªãŒãã³ãœãŒã¹ïŒç¡æ: pywinauto ã¯ãªãŒãã³ãœãŒã¹ãœãããŠã§ã¢ã§ãããå®å šã«ç¡æã§å©çšã§ããŸããã©ã€ã»ã³ã¹è²»çšãæ°ã«ãããå人å©çšããåçšå©çšãŸã§å¹ åºã掻çšå¯èœã§ãã
- Windows ã¢ããªã±ãŒã·ã§ã³ã«ç¹å: Windows ãã€ãã£ãã¢ããªã±ãŒã·ã§ã³ã®æäœã«åŒ·ã¿ãæã£ãŠããŸããç¹ã«ãWin32 API ã Microsoft UI Automation (UIA) ãå©çšããŠãå€ãã®çš®é¡ã®ã¢ããªã±ãŒã·ã§ã³ãå¶åŸ¡ã§ããŸãã
- æè»ãªèŠçŽ ç¹å®æ¹æ³: ãŠã£ã³ããŠããã¿ã³ãããã¹ãããã¯ã¹ãªã©ã® GUI èŠçŽ ïŒã³ã³ãããŒã«ïŒããã¿ã€ãã«ãã¯ã©ã¹åãã³ã³ãããŒã«ID ãªã©æ§ã ãªæ¹æ³ã§ç¹å®ã§ããŸããããã«ãããå€æ§ãªã¢ããªã±ãŒã·ã§ã³ã«å¯Ÿå¿å¯èœã§ãã
- ããã¯ãšã³ãã®éžæ: æäœå¯Ÿè±¡ã®ã¢ããªã±ãŒã·ã§ã³æè¡ã«å¿ããŠã`win32` (Win32 API) ãŸã㯠`uia` (MS UI Automation) ãšãã2ã€ã®ããã¯ãšã³ããéžæã§ããŸããããã«ãããå€ãã¢ããªã±ãŒã·ã§ã³ããæ¯èŒçæ°ããæè¡ïŒWPF, WinForms ãªã©ïŒã§äœãããã¢ããªã±ãŒã·ã§ã³ãŸã§ãå¹ åºã察å¿ã§ããŸãã
- ã·ã³ãã«ãªæäœ: ã¢ããªã±ãŒã·ã§ã³ã®èµ·åããŠã£ã³ããŠã®éžæãã³ã³ãããŒã«ãžã®ã¢ã¯ã·ã§ã³ïŒã¯ãªãã¯ãããã¹ãå ¥åãªã©ïŒããçŽæçã§ç°¡æœãªã³ãŒãã§èšè¿°ã§ããŸãã
ä»ã® RPA ããŒã« (UiPath, Blue Prism ãªã©) ãšæ¯èŒãããšãpywinauto ã¯ã³ãŒãããŒã¹ã§ããããããã°ã©ãã³ã°ç¥èãå¿ èŠã§ããããã®åããã现ããå¶åŸ¡ãå¯èœã§ãã©ã€ã»ã³ã¹è²»çšãããããªããšãã倧ããªã¡ãªããããããŸãã
ð ïž ã€ã³ã¹ããŒã«ãšç°å¢èšå®
pywinauto ã䜿ãå§ããã®ã¯éåžžã«ç°¡åã§ãããŸã㯠Python ç°å¢ã«å¿ èŠãªããã±ãŒãžãã€ã³ã¹ããŒã«ããŸãããã
åææ¡ä»¶
pywinauto ãå©çšããã«ã¯ãPython ãã€ã³ã¹ããŒã«ãããŠããå¿ èŠããããŸããå ¬åŒããã¥ã¡ã³ãã«ãããšãPython 3.6 以äžãæšå¥šãããŠããŸã (ææ°çã§ã¯ Python 3.7 以éãå¿ èŠãªå ŽåããããŸã)ããŸã Python ãã€ã³ã¹ããŒã«ããŠããªãå Žåã¯ãPython å ¬åŒãµã€ã ããããŠã³ããŒãããŠã€ã³ã¹ããŒã«ããŠãã ããã
ãŸããéçºãé²ããäžã§ã¯ããããžã§ã¯ãããšã«ç°å¢ãåé¢ã§ãããä»®æ³ç°å¢ãã®å©çšã匷ãæšå¥šããŸããä»®æ³ç°å¢ã䜿ãããšã§ãã©ã€ãã©ãªã®ããŒãžã§ã³ç«¶åãªã©ãé²ãããšãã§ããŸãã
# ä»®æ³ç°å¢ãäœæ (äŸ: .venv ãšããååã®ä»®æ³ç°å¢)
python -m venv .venv
# ä»®æ³ç°å¢ãã¢ã¯ãã£ããŒã (Windowsã®å Žå)
.\.venv\Scripts\activate
# (Linux/macOSã®å Žå)
# source .venv/bin/activate
pip ã䜿ã£ãã€ã³ã¹ããŒã«
Python ç°å¢ïŒã§ããã°ã¢ã¯ãã£ããŒããããä»®æ³ç°å¢ïŒãæºåã§ããããpip ã³ãã³ãã䜿ã£ãŠ pywinauto ãã€ã³ã¹ããŒã«ããŸãã
pip install -U pywinauto
-U
ãªãã·ã§ã³ã¯ãæ¢ã«ã€ã³ã¹ããŒã«ãããŠããå Žåã«ææ°çãžã¢ããã°ã¬ãŒãããããã®ãã®ã§ãã
ãŸããã³ã³ãããŒã«ã®ã¹ã¯ãªãŒã³ã·ã§ãããååŸããæ©èœ (`capture_as_image()`) ãå©çšãããå Žåã¯ãç»ååŠçã©ã€ãã©ãª Pillow ãã€ã³ã¹ããŒã«ããå¿ èŠããããŸãã
pip install Pillow
ãã㧠pywinauto ã䜿çšããæºåãæŽããŸããïŒð
𧩠åºæ¬çãªæŠå¿µ
pywinauto ãå¹æçã«äœ¿ãããã«ã¯ãããã€ãã®åºæ¬çãªæŠå¿µãç解ããŠããããšãéèŠã§ãã
ããã¯ãšã³ã (Backend)
pywinauto ã Windows ã¢ããªã±ãŒã·ã§ã³ãšéä¿¡ããGUI èŠçŽ ãæäœããããã®åºç€ãšãªãæè¡ã§ããäž»ã«ä»¥äžã®2çš®é¡ããããŸãã
win32
(Win32 API): å€ããããã Windows ã®æšæº API ã§ããMFC, VB6, VCL ãªã©ã§äœãããã¬ã¬ã·ãŒãªã¢ããªã±ãŒã·ã§ã³ããäžéšã® WinForms ã¢ããªã±ãŒã·ã§ã³ã®æäœã«é©ããŠããŸããããã©ã«ãã®ããã¯ãšã³ãã§ããæ¯èŒç軜éã§é«éã«åäœããããšããããŸããuia
(Microsoft UI Automation): ããæ°ããã¢ã¯ã»ã·ããªãã£æè¡ã§ããWinForms, WPF, Qt, ãã©ãŠã¶ãªã©ãããã¢ãã³ãªæè¡ã§éçºãããã¢ããªã±ãŒã·ã§ã³ã®æäœã«é©ããŠããŸããwin32
ã§ã¯èªèã§ããªãã³ã³ãããŒã«ãèªèã§ããå ŽåããããŸãã
ã©ã¡ãã®ããã¯ãšã³ãã䜿çšãããã¯ãæäœå¯Ÿè±¡ã®ã¢ããªã±ãŒã·ã§ã³ã«ãã£ãŠéžæããŸããã¢ããªã±ãŒã·ã§ã³ã®èµ·åæãæ¥ç¶æã« backend="win32"
ãŸã㯠backend="uia"
ã®ããã«æå®ããŸãã
ãšã³ããªãŒãã€ã³ã (Entry Point)
èªååæäœã®èµ·ç¹ãšãªããªããžã§ã¯ãã§ããäž»ã«2ã€ã®ã¯ã©ã¹ããããŸãã
Application
: ç¹å®ã®ã¢ããªã±ãŒã·ã§ã³ããã»ã¹ã«æ¥ç¶ãããã®ããã»ã¹å ã®ãŠã£ã³ããŠãã³ã³ãããŒã«ãæäœããŸããã¢ããªã±ãŒã·ã§ã³ã®èµ·å (start()
) ããæ¢ã«å®è¡äžã®ããã»ã¹ãžã®æ¥ç¶ (connect()
) ã«äœ¿çšããŸããããã»ã¹ãè·šãã æäœã¯åºæ¬çã«è¡ããŸãããDesktop
: ãã¹ã¯ãããå šäœãæäœå¯Ÿè±¡ãšããŸããç¹å®ã®ããã»ã¹ã«éå®ãããè€æ°ã®ã¢ããªã±ãŒã·ã§ã³ãããã»ã¹ã«ãŸããããŠã£ã³ããŠãæäœããå Žåã«äœ¿çšããŸããããã¯ãšã³ããæå®ããŠåæåããŸã (äŸ:Desktop(backend="uia")
)ã
ãŠã£ã³ããŠ à€žà¥à€ªà¥à€žà€¿à€«à€¿à€à¥à€¶à€š (Window Specification)
æäœããããŠã£ã³ããŠïŒãã€ã¢ãã°ãå«ãïŒãäžæã«ç¹å®ããããã®æ
å ±ã§ããApplication
ãªããžã§ã¯ãã Desktop
ãªããžã§ã¯ãã«ç¶ããŠãè§æ¬åŒ§ []
ãããã .
ã䜿ã£ãŠãŠã£ã³ããŠãæå®ããŸãã
ãŠã£ã³ããŠã®ç¹å®ã«ã¯ã以äžã®ãããªæ å ±ãå©çšã§ããŸãã
- ã¿ã€ãã« (Window Text)
- ã¯ã©ã¹å (Class Name)
- æé©ãªäžèŽ (Best Match)
- æ£èŠè¡šçŸ
äŸ: app["ã¡ã¢åž³"]
, app.UntitledNotepad
, app.window(title_re=".*ã¡ã¢åž³")
ã³ã³ãããŒã« (Control)
ãŠã£ã³ããŠå ã®ãã¿ã³ãããã¹ãããã¯ã¹ããªã¹ãããã¯ã¹ãã¡ãã¥ãŒãªã©ã®åã ã® GUI èŠçŽ ã§ããWindow Specification ãšåæ§ã«ãè§æ¬åŒ§ããããã䜿ã£ãŠã¢ã¯ã»ã¹ããŸãã
ã³ã³ãããŒã«ã®ç¹å®ã«ã¯ã以äžã®ãããªæ å ±ãå©çšã§ããŸãã
- ããã¹ã (Title, Label)
- ã¯ã©ã¹å (Class Name)
- ã³ã³ãããŒã«ã¿ã€ã (Control Type, `uia` ããã¯ãšã³ãã§æå¹)
- èªåå ID (Automation ID, `uia` ããã¯ãšã³ãã§æå¹)
- ã€ã³ããã¯ã¹çªå·
äŸ: dlg["OK"]
, dlg.OKButton
, dlg.Edit
, dlg.child_window(auto_id="CalculatorResults", control_type="Text")
ð å®è·µïŒpywinauto ã®åºæ¬çãªäœ¿ãæ¹
ããã§ã¯ãå®éã« pywinauto ã䜿ã£ãŠç°¡å㪠Windows ã¢ããªã±ãŒã·ã§ã³ïŒã¡ã¢åž³ïŒãæäœããŠã¿ãŸãããã
1. ã©ã€ãã©ãªã®ã€ã³ããŒã
ãŸããå¿ èŠãª `Application` ã¯ã©ã¹ãã€ã³ããŒãããŸãã
from pywinauto.application import Application
2. ã¢ããªã±ãŒã·ã§ã³ã®èµ·å
`Application` ã¯ã©ã¹ã® `start()` ã¡ãœããã䜿ã£ãŠãã¡ã¢åž³ (notepad.exe) ãèµ·åããŸããããã§ã¯ `uia` ããã¯ãšã³ããæå®ããŠã¿ãŸãã
# uia ããã¯ãšã³ããæå®ããŠã¡ã¢åž³ãèµ·å
app = Application(backend="uia").start("notepad.exe")
# ããã©ã«ãã® win32 ããã¯ãšã³ãã§èµ·åããå Žå
# app = Application().start("notepad.exe")
3. ãŠã£ã³ããŠã®ç¹å®ãšæäœ
èµ·åããã¡ã¢åž³ã®ãŠã£ã³ããŠãç¹å®ããæäœããŸãããŠã£ã³ããŠã®ã¿ã€ãã«ã¯ç°å¢ã«ãã£ãŠç°ãªãå Žåããããã泚æãå¿ èŠã§ãïŒäŸ: “ç¡é¡ – ã¡ã¢åž³”, “Untitled – Notepad”ïŒã
# ãŠã£ã³ããŠã¿ã€ãã«ã§ãŠã£ã³ããŠãååŸ (å®éã®ã¿ã€ãã«ã«åãããŠå€æŽ)
# æ¥æ¬èªç°å¢ã®å Žå: dlg = app["ç¡é¡ - ã¡ã¢åž³"]
# è±èªç°å¢ã®å Žå: dlg = app.UntitledNotepad
dlg = app.window(title_re=".*ã¡ã¢åž³") # æ£èŠè¡šçŸã§ã¿ã€ãã«ã«ãã¡ã¢åž³ããå«ãŸãããŠã£ã³ããŠãæ¢ã
# ãŠã£ã³ããŠã衚瀺ããããŸã§åŸ
æ© (æšå¥š)
dlg.wait('visible')
# ã¡ãã¥ãŒãéžæ ("ãã«ã" -> "ããŒãžã§ã³æ
å ±")
# æ¥æ¬èªç°å¢: dlg.menu_select("ãã«ã(&H)->ããŒãžã§ã³æ
å ±(&A)")
# è±èªç°å¢: dlg.menu_select("Help->About Notepad")
dlg.menu_select("ãã«ã(&H)->ããŒãžã§ã³æ
å ±(&A)")
# "ããŒãžã§ã³æ
å ±" ãã€ã¢ãã°ã衚瀺ãããã®ãåŸ
ã€
about_dlg = app.window(title="ããŒãžã§ã³æ
å ±") # ãŸã㯠title="About Notepad"
about_dlg.wait('visible')
# "OK" ãã¿ã³ãã¯ãªãã¯
# ãã¿ã³ã®ããã¹ãã§æå®: about_dlg["OK"].click()
# ã³ã³ãããŒã«ã¿ã€ããšããã¹ãã§æå®: about_dlg.OKButton.click()
about_dlg["OK"].click()
# ã¡ã¢åž³ã®ãšãã£ããã³ã³ãããŒã«ã«ããã¹ããå
¥å
# ã³ã³ãããŒã«ã¿ã€ãã§æå®: dlg.Edit.type_keys("pywinauto ã¯æ¥œããïŒð", with_spaces=True)
# ã¿ã€ãã«ã§æå® (ããããã°): dlg["ããã¹ã ãšãã£ã¿ãŒ"].type_keys("pywinauto works!ð", with_spaces=True)
# æ¥æ¬èªå
¥åã®å Žå㯠set_edit_text ã®æ¹ã確å®ãªå Žåããã
try:
# ãŸã Edit ã³ã³ãããŒã«ãæ¢ã
edit_control = dlg.child_window(class_name="Edit")
edit_control.set_edit_text("pywinauto ã§èªåå
¥åãã¹ãã")
except Exception as e:
print(f"ãšãã£ããã³ã³ãããŒã«ãèŠã€ãããªãããããã¹ãèšå®ã§ãšã©ãŒ: {e}")
# Modern ãªã¡ã¢åž³ (UWP) ã®å Žåãã³ã³ãããŒã«æ§é ãç°ãªãå¯èœæ§ããã
# ãã®å Žå㯠AutomationId ã ControlType ã§æ¢ãå¿
èŠããã
try:
# äŸ: UWP ã¡ã¢åž³ã®ããã¹ãé å (AutomationId 㯠Inspect.exe ãªã©ã§ç¢ºèª)
edit_control_uwp = dlg.child_window(auto_id="RichEditBox") # ããã¯äžäŸãå®éã®IDã¯ç°ãªãå¯èœæ§ãã
edit_control_uwp.type_keys("pywinauto ã§èªåå
¥åãã¹ã (UWP)ã", with_spaces=True)
except Exception as e_uwp:
print(f"UWPã¡ã¢åž³ã®ãšãã£ããã³ã³ãããŒã«ãèŠã€ãããªããããšã©ãŒ: {e_uwp}")
# ã¢ããªã±ãŒã·ã§ã³ãéãã (å€æŽãä¿åããã«éãã)
dlg.close(wait_time=1) # å°ãåŸ
æ©æéãèšãã
ãã®äŸã§ã¯ãã¡ã¢åž³ãèµ·åããã¡ãã¥ãŒæäœã§ãããŒãžã§ã³æ å ±ããã€ã¢ãã°ãéããŠéããæåŸã«ãšãã£ããé åã«ããã¹ããå ¥åããŠçµäºããããšããäžé£ã®æµããèªååããŠããŸãã`wait(‘visible’)` ã䜿ãããšã§ããŠã£ã³ããŠããã€ã¢ãã°ãå®éã«è¡šç€ºããããŸã§åŸ æ©ãããããšãã§ããã¹ã¯ãªããã®å®å®æ§ãåäžããŸãã
泚æ: ãŠã£ã³ããŠã®ã¿ã€ãã«ãã¡ãã¥ãŒã®ããã¹ãã¯ãOS ã®èšèªèšå®ã«ãã£ãŠç°ãªããŸããäžèšã®ã³ãŒãã¯æ¥æ¬èªç°å¢ãæ³å®ããŠããéšåããããŸãã®ã§ãè±èªç°å¢ãªã©ã§ã¯é©å®ä¿®æ£ãå¿ èŠã§ãããŸããWindows ã®ããŒãžã§ã³ãã¡ã¢åž³ã¢ããªã®ããŒãžã§ã³ïŒåŸæ¥ã® Win32 çããã¹ãã¢ã¢ããªçããªã©ïŒã«ãã£ãŠãã³ã³ãããŒã«ã®æ§é ãååãç°ãªãå ŽåããããŸãã
ð ãŠã£ã³ããŠãšã³ã³ãããŒã«ã®ç¹å®æ¹æ³
èªååã®ç²ŸåºŠãé«ããããã«ã¯ãæäœå¯Ÿè±¡ã®ãŠã£ã³ããŠãã³ã³ãããŒã«ãæ£ç¢ºã«ç¹å®ããããšãäžå¯æ¬ ã§ããpywinauto ã¯è±å¯ãªç¹å®æ¹æ³ãæäŸããŠããŸãã
ç¹å®ã®ããã®å±æ§
ãŠã£ã³ããŠãã³ã³ãããŒã«ãç¹å®ããããã«ã以äžã®ãããªå±æ§ïŒèå¥åïŒãçµã¿åãããŠäœ¿çšããŸãã
å±æ§å (åŒæ°å) | 説æ | äŸ | ããã¯ãšã³ã |
---|---|---|---|
title |
ãŠã£ã³ããŠã®ã¿ã€ãã«ããŒã®ããã¹ãããã³ã³ãããŒã«ã®ã©ãã«ããã¹ãã | app.window(title="ã¡ã¢åž³") , dlg["OK"] |
win32, uia |
class_name |
ãŠã£ã³ããŠãŸãã¯ã³ã³ãããŒã«ã®ãŠã£ã³ããŠã¯ã©ã¹åã | app.window(class_name="Notepad") , dlg.child_window(class_name="Edit") |
win32, uia |
control_type |
UI Automation ã§å®çŸ©ãããã³ã³ãããŒã«ã®çš®é¡ (Button, Edit, Text, Pane ãªã©)ã | dlg.child_window(control_type="Button", title="ä¿å") |
uia |
auto_id |
UI Automation ã§å®çŸ©ãããäžæã®èå¥å (éçºè ãèšå®)ã | dlg.child_window(auto_id="SaveButton") |
uia |
control_id |
Win32 ã§å®çŸ©ãããã³ã³ãããŒã«ã®æ°å€ IDã | dlg.child_window(control_id=1001) |
win32 |
title_re |
ã¿ã€ãã«ãæ£èŠè¡šçŸã§æ€çŽ¢ã | app.window(title_re=".*ã¡ã¢åž³.*") |
win32, uia |
class_name_re |
ã¯ã©ã¹åãæ£èŠè¡šçŸã§æ€çŽ¢ã | app.window(class_name_re=".*Notepad.*") |
win32, uia |
best_match |
æå®ããæååã«æãè¿ãã¿ã€ãã«ãããã¹ããæã€èŠçŽ ãæ€çŽ¢ã | app.window(best_match="ç¡é¡ ã¡ã¢åž³") |
win32, uia |
visible_only |
衚瀺ãããŠããèŠçŽ ã®ã¿ã察象ãšããã (ããã©ã«ã: True)ã | app.window(title="é衚瀺ãŠã£ã³ããŠ", visible_only=False) |
win32, uia |
enabled_only |
æå¹ãªïŒæäœå¯èœãªïŒèŠçŽ ã®ã¿ã察象ãšããã (ããã©ã«ã: False)ã | dlg.child_window(title="OK", enabled_only=True) |
win32, uia |
ãããã®å±æ§ã¯ãapp.window(...)
ã dlg.child_window(...)
ã®ããã«ãããŒã¯ãŒãåŒæ°ãšããŠæå®ããŸãããŸããapp["ã¿ã€ãã«"]
ã dlg.ã³ã³ãããŒã«å
ã®ãããªç°¡æçãªèšæ³ãå©çšã§ããŸãããããã¯å
éšçã« best_match ã title/control_type ãªã©ã䜿ã£ãŠæ€çŽ¢ããŠããŸããããå³å¯ã«æå®ãããå Žå㯠window()
ã child_window()
ã¡ãœããã䜿çšããŸãã
èå¥åã®èª¿æ»æ¹æ³: print_control_identifiers()
ç¹å®ã®ãŠã£ã³ããŠãã³ã³ãããŒã«ã«ãã©ã®ãããªèå¥åãå©çšå¯èœãã確èªãããå Žåãprint_control_identifiers()
ã¡ãœãããéåžžã«åœ¹ç«ã¡ãŸãã
# ã¡ã¢åž³ã®ã¡ã€ã³ãŠã£ã³ããŠã®èå¥åã衚瀺
dlg = app.window(title_re=".*ã¡ã¢åž³")
dlg.print_control_identifiers()
# ãã "ãã¡ã€ã«" ã¡ãã¥ãŒãããã°ããã®èå¥åã衚瀺
try:
file_menu = dlg.child_window(title="ãã¡ã€ã«", control_type="MenuItem")
file_menu.print_control_identifiers()
except Exception as e:
print(f"ãã¡ã€ã«ã¡ãã¥ãŒãèŠã€ãããŸãã: {e}")
ãã®ã¡ãœãããå®è¡ãããšããã®èŠçŽ ã«ã¢ã¯ã»ã¹ããããã«å©çšå¯èœãªæ§ã ãªå±æ§ïŒã¿ã€ãã«ãã¯ã©ã¹åãèªååIDãªã©ïŒãšãã®å€ãã³ã³ãœãŒã«ã«åºåãããŸãããããèŠãã°ãã¹ã¯ãªããã§ã©ã®èå¥åã䜿ãã®ãæé©ãå€æãããããªããŸããâš
GUI ã€ã³ã¹ãã¯ã·ã§ã³ããŒã«
ã³ãŒãããã ãã§ãªããå°çšã®ããŒã«ã䜿ã£ãŠ GUI èŠçŽ ã®æ å ±ã調æ»ããããšãæå¹ã§ãã
- Inspect.exe (UI Automation Verify): Microsoft ãæäŸãã UI Automation ã®ããã®ã€ã³ã¹ãã¯ã·ã§ã³ããŒã«ãWindows SDK ã«å«ãŸããŠããŸããã³ã³ãããŒã«ã®éå±€æ§é ããããã㣠(AutomationId, ControlType, Name ãªã©) ã詳现ã«ç¢ºèªã§ããŸãã`uia` ããã¯ãšã³ãå©çšæã«ç¹ã«åœ¹ç«ã¡ãŸãã
- Spy++: Microsoft Visual Studio ã«ä»å±ããããŒã«ãWin32 API ããŒã¹ã®ãŠã£ã³ããŠã¡ãã»ãŒãžããŠã£ã³ããŠ/ã³ã³ãããŒã«ã®ãããã㣠(ã¯ã©ã¹åãã³ã³ãããŒã«IDãªã©) ã調æ»ã§ããŸãã`win32` ããã¯ãšã³ãå©çšæã«åœ¹ç«ã¡ãŸãã
- py_inspect.py: pywinauto ã«å«ãŸããå®éšçãªããŒã«ãã³ãã³ãã©ã€ã³ããå®è¡ããããŠã¹ã«ãŒãœã«äžã®ã³ã³ãããŒã«æ å ±ã衚瀺ããŸãã
ãããã®ããŒã«ã䜿ã£ãŠãç®çã®ã³ã³ãããŒã«ãã©ã®ãããªå±æ§ãæã£ãŠããããäºåã«èª¿ã¹ãŠãããšãã¹ã¯ãªããäœæãã¹ã ãŒãºã«é²ã¿ãŸãã
ð±ïž ã³ã³ãããŒã«ã®æäœ
ãŠã£ã³ããŠãã³ã³ãããŒã«ãç¹å®ã§ãããã次ã¯ããããæäœããŸããpywinauto ã¯æ§ã ãªæäœã¡ãœãããæäŸããŠããŸãã
ã¯ãªãã¯æäœ
ãã¿ã³ãªã©ã®ã³ã³ãããŒã«ãã¯ãªãã¯ããã«ã¯ãclick()
ã click_input()
ã¡ãœããã䜿çšããŸãã
# OK ãã¿ã³ãã¯ãªã㯠(æãäžè¬çãªæ¹æ³)
dlg.child_window(title="OK", control_type="Button").click()
# ããŠã¹ã«ãŒãœã«ãåãããŠã¯ãªã㯠(ãã人éã«è¿ãæäœ)
# coords=(x, y) ã§ã¯ãªãã¯äœçœ®ã®ãªãã»ãããæå®å¯èœ
dlg.child_window(title="ãã£ã³ã»ã«", control_type="Button").click_input()
# ããã«ã¯ãªãã¯
dlg.child_window(title="ãã¡ã€ã«ãéã", control_type="ListItem").double_click_input()
click()
ã¯æ¯èŒçæ©ããå
éšçãªã¡ãã»ãŒãžéä¿¡ã§ã¯ãªãã¯ãè©Šã¿ãŸããclick_input()
ã¯å®éã«ããŠã¹ã«ãŒãœã«ã移åãããŠã¯ãªãã¯ããããããã確å®ã§ããå°ãæéããããããšããããŸããã¢ããªã±ãŒã·ã§ã³ã«ãã£ãŠã¯ã©ã¡ããäžæ¹ããå¹ããªãå ŽåããããŸãã
ããã¹ãå ¥å
ããã¹ãããã¯ã¹ (Edit ã³ã³ãããŒã«ãªã©) ã«æåãå
¥åããã«ã¯ãtype_keys()
ã set_edit_text()
ã䜿çšããŸãã
# ãŠãŒã¶ãŒåãã£ãŒã«ãã«ããã¹ããå
¥å
dlg.child_window(auto_id="UserNameEdit").type_keys("my_username", with_spaces=True)
# ãã¹ã¯ãŒããã£ãŒã«ãã«ããã¹ããå
¥å (ç¹æ®æåã修食ããŒãå¯èœ)
# {} ã§å²ããšç¹æ®ããŒãæå®: {ENTER}, {TAB}, {F5}, ^ (Ctrl), + (Shift), % (Alt)
dlg.child_window(auto_id="PasswordEdit").type_keys("my^secret+pass{TAB}", with_tabs=True) # Ctrl+secret+Shift+pass ãå
¥åã Tab
# ããã¹ããçŽæ¥èšå® (æ¥æ¬èªãªã©è€éãªæåå
¥åã«æå¹ãªå Žåããã)
# 泚æ: æ¢åã®ããã¹ãã¯äžæžãããã
dlg.child_window(class_name="Edit").set_edit_text("ããã¯èšå®ãããããã¹ãã§ãã")
# çŸåšã®ããã¹ããååŸ
current_text = dlg.child_window(class_name="Edit").window_text()
print(f"çŸåšã®ããã¹ã: {current_text}")
type_keys()
ã¯ããŒããŒãããã®å
¥åãã·ãã¥ã¬ãŒãããŸããwith_spaces=True
ã§ã¹ããŒã¹ãå
¥åãwith_tabs=True
ã§ã¿ãæåãå
¥åã§ããŸããç¹æ®ããŒã®çµã¿åãããå¯èœã§ãã
set_edit_text()
ã¯ã³ã³ãããŒã«ã®ããã¹ãããããã£ãçŽæ¥èšå®ããŸããããŒããŒãã€ãã³ããçºçããªããããã¢ããªã±ãŒã·ã§ã³ã«ãã£ãŠã¯å
¥åãšããŠèªèãããªãå ŽåããããŸãããæ¥æ¬èªãªã©ã®ãã«ããã€ãæåã確å®ã«å
¥åãããå Žåã«æå¹ãªããšããããŸãã
ãã®ä»ã®ã³ã³ãããŒã«æäœ
- ãã§ãã¯ããã¯ã¹ (CheckBox):
checkbox = dlg.child_window(title="åæãã", control_type="CheckBox") checkbox.toggle() # ç¶æ ãå転 if not checkbox.is_checked(): checkbox.check() # ãã§ãã¯ãã if checkbox.is_checked(): checkbox.uncheck() # ãã§ãã¯ãå€ã
- ã©ãžãªãã¿ã³ (RadioButton):
radio_button = dlg.child_window(title="ãªãã·ã§ã³B", control_type="RadioButton") radio_button.select() # éžæãã is_selected = radio_button.is_selected() print(f"ãªãã·ã§ã³Bã¯éžæãããŠããŸããïŒ {is_selected}")
- ã³ã³ãããã¯ã¹ (ComboBox) / ãªã¹ãããã¯ã¹ (ListBox):
combo = dlg.child_window(auto_id="CountryComboBox") combo.select("Japan") # ããã¹ãã§éžæ combo.select(2) # ã€ã³ããã¯ã¹ã§éžæ (0å§ãŸã) listbox = dlg.child_window(class_name="ListBox") listbox.select("é ç®3") selected_items = listbox.selected_texts() print(f"éžæäžã®é ç®: {selected_items}")
- ã¡ãã¥ãŒ (Menu / MenuItem):
# ã¡ã€ã³ãŠã£ã³ããŠã®ã¡ãã¥ãŒãéžæ dlg.menu_select("ãã¡ã€ã«(&F)->ååãä»ããŠä¿å(&A)...") # ã³ã³ããã¹ãã¡ãã¥ãŒãªã©ãæäœããå Žå (MenuItemã³ã³ãããŒã«ãšããŠååŸ) # (äºåã«å³ã¯ãªãã¯ãªã©ã§ã¡ãã¥ãŒã衚瀺ãããŠããå¿ èŠãã) # app.PopupMenu.menu_select("ã³ããŒ(&C)")
- ãŠã£ã³ããŠã®æ倧åã»æå°åã»ã¢ã¯ãã£ãå:
dlg.maximize() # æ倧å time.sleep(1) dlg.minimize() # æå°å time.sleep(1) dlg.restore() # å ã®ãµã€ãºã«æ»ã dlg.set_focus() # ãŠã£ã³ããŠãã¢ã¯ãã£ãã«ãã (åé¢ã«åºã)
- ãŠã£ã³ããŠã®ç§»åã»ãªãµã€ãº:
# æå®ããåº§æš (å·Šäžé ) ã«ç§»å dlg.move_window(x=100, y=100) time.sleep(1) # ãµã€ãºãåæã«å€æŽ dlg.move_window(x=0, y=0, width=800, height=600, repaint=True)
ãããã¯äžéšã®äŸã§ããæäœãããã³ã³ãããŒã«ã®çš®é¡ã«å¿ããŠãé©åãªã¡ãœãããéžæããŠãã ãããã³ã³ãããŒã«ãã©ã®ãããªã¡ãœãããæã£ãŠãããã¯ãprint_control_identifiers()
ã®åºåãå
¬åŒããã¥ã¡ã³ãã§ç¢ºèªã§ããŸãã
ð¡ å¿çšãã¯ããã¯ãšæ³šæç¹
åºæ¬çãªæäœã«æ £ããŠããããããé«åºŠãªãã¯ããã¯ã泚æç¹ãæŒãããŠãããŸãããã
åŸ æ©åŠç (Wait)
GUI ãªãŒãã¡ãŒã·ã§ã³ã§ã¯ãã¢ããªã±ãŒã·ã§ã³ã®å¿çé床ãäºæãã¬ãã€ã¢ãã°ã®è¡šç€ºãªã©ã«ãããã¿ã€ãã³ã°ã®åé¡ãçºçããããã§ããç¹å®ã®ç¶æ ã«ãªããŸã§åŸ æ©ããåŠçãå ¥ããããšã§ãã¹ã¯ãªããã®å®å®æ§ãå€§å¹ ã«åäžãããããšãã§ããŸãã
from pywinauto.timings import TimeoutError
import time
try:
# "ä¿å" ãã¿ã³ãæå¹ã«ãªããŸã§æ倧10ç§åŸ
æ©
dlg.child_window(title="ä¿å", control_type="Button").wait('enabled', timeout=10)
print("ä¿åãã¿ã³ãæå¹ã«ãªããŸããã")
# "åŠçäž..." ãšããããã¹ããæ¶ãããŸã§æ倧30ç§åŸ
æ©
dlg.child_window(title="åŠçäž...", control_type="Text").wait_not('visible', timeout=30)
print("åŠçãå®äºããŸããã")
# ç¹å®ã®ãŠã£ã³ããŠãåºçŸãããŸã§åŸ
æ©
app.window(title="å®äºéç¥").wait('exists visible', timeout=15)
print("å®äºéç¥ãã€ã¢ãã°ã衚瀺ãããŸããã")
except TimeoutError:
print("ã¿ã€ã ã¢ãŠããšã©ãŒ: æå®æéå
ã«æåŸ
ããç¶æ
ã«ãªããŸããã§ããã")
except Exception as e:
print(f"åŸ
æ©äžã«ãšã©ãŒãçºçããŸãã: {e}")
# åçŽãªåºå®æéåŸ
æ© (éæšå¥šã ããç°¡åãªèª¿æŽã«ã¯äœ¿ãã)
time.sleep(2) # 2ç§åŸ
æ©
wait(wait_for, timeout, retry_interval)
ã¡ãœããã¯éåžžã«åŒ·åã§ããwait_for
ã«ã¯åŸ
æ©ãããç¶æ
ãæå®ããŸãïŒäŸ: 'visible'
, 'enabled'
, 'ready'
, 'exists'
ïŒãwait_not(...)
ã¯éã«ãæå®ããç¶æ
ã§ãªããªããŸã§åŸ
æ©ããŸããé©åãªåŸ
æ©åŠçãçµã¿èŸŒãããšããå
ç¢ãªèªååã¹ã¯ãªããã®éµãšãªããŸãðã
ãšã©ãŒãã³ããªã³ã°
èªååã¹ã¯ãªããã¯ãäºæãã¬ç¶æ³ïŒãŠã£ã³ããŠãèŠã€ãããªããã³ã³ãããŒã«ãç¡å¹ã«ãªã£ãŠãããªã©ïŒã«ééããå¯èœæ§ããããŸããtry...except
ãããã¯ã䜿ã£ãŠããããã®ãšã©ãŒãé©åã«åŠçããããšãéèŠã§ãã
from pywinauto.findwindows import ElementNotFoundError
from pywinauto.findbestmatch import MatchError
try:
# ãŠã£ã³ããŠãã³ã³ãããŒã«ãæ¢ãåŠç
main_window = app.window(title="ååšããªããŠã£ã³ããŠ")
main_window.child_window(title="ååšããªããã¿ã³").click()
except (ElementNotFoundError, MatchError) as e:
print(f"ãšã©ãŒ: ãŠã£ã³ããŠãŸãã¯ã³ã³ãããŒã«ãèŠã€ãããŸããã§ããã詳现: {e}")
# ããã§ãšã©ãŒå埩åŠçããã°èšé²ãªã©ãè¡ã
except Exception as e:
print(f"äºæãã¬ãšã©ãŒãçºçããŸãã: {e}")
# å¿
èŠã«å¿ããŠã¹ã¿ãã¯ãã¬ãŒã¹ãªã©ãèšé²
finally:
print("åŠçãçµäºããŸãã")
# å¿
èŠã§ããã°ãã¢ããªã±ãŒã·ã§ã³ãéãããªã©ã®ã¯ãªãŒã³ã¢ããåŠç
# app.kill() # 匷å¶çµäº
ElementNotFoundError
ã MatchError
ã¯ãèŠçŽ ãèŠã€ãããªãã£ãå Žåã«çºçãã代衚çãªäŸå€ã§ããããããææããç¶æ³ã«å¿ããåŠçïŒãªãã©ã€ãã¹ãããããšã©ãŒéç¥ãªã©ïŒãå®è£
ããããšã§ãã¹ã¯ãªããå
šäœã®å®å®æ§ãé«ããããšãã§ããŸãã
ããã¯ãšã³ãã®éžæã«é¢ãã泚æç¹
åè¿°ã®éããwin32
ãš uia
ã®ã©ã¡ãã®ããã¯ãšã³ããéžæãããã¯éèŠã§ãã
- åºæ¬çã«ã¯ããŸãããã©ã«ãã®
win32
ã§è©ŠããŠã¿ãŠãããŸãã³ã³ãããŒã«ãèªèã»æäœã§ããªãå Žåã«uia
ãè©Šãã®ãè¯ãã§ãããã - WPF ã UWP (ã¹ãã¢ã¢ããª) ãªã©ãæ¯èŒçæ°ããæè¡ã§äœãããã¢ããªã±ãŒã·ã§ã³ã¯
uia
ããã¯ãšã³ãã§ãªããšæäœã§ããªãããšãå€ãã§ãã - äžæ¹ãéåžžã«å€ãã¢ããªã±ãŒã·ã§ã³ãç¹å®ã®ã«ã¹ã¿ã ã³ã³ãããŒã«ã¯
win32
ã§ãªããšã¢ã¯ã»ã¹ã§ããªãå ŽåããããŸãã - Inspect.exe ãªã©ã®ããŒã«ã䜿ã£ãŠã察象ã¢ããªã±ãŒã·ã§ã³ã®ã³ã³ãããŒã«ãã©ã¡ãã®æè¡ã§èªèããããããã確èªããã®ã確å®ã§ããInspect.exe ã®å·Šäžã®ã¡ãã¥ãŒã§ “UI Automation” / “MSAA” (Win32ã«è¿ã) ãåãæ¿ããŠç¢ºèªã§ããŸãã
- 1ã€ã®ã¹ã¯ãªããå
ã§äž¡æ¹ã®ããã¯ãšã³ããæ··åšãããããšã¯æšå¥šãããŸãããåºæ¬çã«ã¯ã
Application
ãŸãã¯Desktop
ãªããžã§ã¯ããåæåããéã«ã©ã¡ããäžæ¹ãæå®ããŸãã
ããŒããŒãã·ã§ãŒãã«ããã®æŽ»çš
ããŠã¹æäœã ãã§ãªããã¢ããªã±ãŒã·ã§ã³ãæäŸããããŒããŒãã·ã§ãŒãã«ãããå©çšãããšãããé«éã§å®å®ããæäœãå¯èœãªå ŽåããããŸããtype_keys()
ã¡ãœããã§ä¿®é£ŸããŒïŒCtrl, Alt, ShiftïŒãšçµã¿åãããããŒå
¥åãéä¿¡ã§ããŸãã
# Ctrl + S ã§ä¿åããå Žå
dlg.type_keys('^s')
# Alt + F4 ã§ãŠã£ã³ããŠãéããå Žå
dlg.type_keys('%{F4}')
ãã°ãšãããã°
è€éãªèªååã¹ã¯ãªãããäœæããå Žåãäœãèµ·ãã£ãŠããããææ¡ããããã«ãã°åºåã圹ç«ã¡ãŸããPython ã® `logging` ã¢ãžã¥ãŒã«ãªã©ã掻çšããŸãããããŸããåé¡çºçæã®ãããã°ã«ã¯ã`print_control_identifiers()` ã GUI ã€ã³ã¹ãã¯ã·ã§ã³ããŒã«ãäžå¯æ¬ ã§ããã¹ãããå®è¡ããªããå€æ°ã®ç¶æ ã確èªããããšãæå¹ã§ãã
ð ãŸãšã
pywinauto ã¯ãPython ã䜿ã£ãŠ Windows GUI æäœãèªååããããã®éåžžã«åŒ·åã§æè»ãªã©ã€ãã©ãªã§ãããã®èšäºã§ã¯ããã®åºæ¬çãªæŠå¿µããã€ã³ã¹ããŒã«ãäž»èŠãªæäœæ¹æ³ããããŠå¿çšçãªãã¯ããã¯ã泚æç¹ã«ã€ããŠè§£èª¬ããŸããã
pywinauto ã掻çšããããšã§ã以äžã®ãããªã¡ãªãããæåŸ ã§ããŸãã
- åçŽãªç¹°ãè¿ãäœæ¥ããã®è§£æŸãšæéç¯çŽ â±ïž
- æäœæ¥ã«ãããã¹ã®åæž ð
- GUI ã¢ããªã±ãŒã·ã§ã³ã®èªåãã¹ãã«ããå質åäž ð§ª
- æ¢åã·ã¹ãã ãæ¹ä¿®ããã« RPA ãå®çŸ ð€
ãã¡ãããGUI ãªãŒãã¡ãŒã·ã§ã³ã¯å¯Ÿè±¡ã¢ããªã±ãŒã·ã§ã³ã® UI å€æŽã«åŒ±ããšããåŽé¢ããããŸãããé©åãªåŸ æ©åŠçããšã©ãŒãã³ããªã³ã°ããããŠããŒãžã§ã³ç®¡çãªã©ãçµã¿åãããããšã§ãååã«å®çšçãªèªååãœãªã¥ãŒã·ã§ã³ãæ§ç¯ã§ããŸãã
ãã²ã身ã®åãã®å®åç㪠Windows æäœã pywinauto ã§èªååããããšã«ææŠããŠã¿ãŠãã ãããæåã¯ç°¡åãªæäœããå§ããåŸã ã«è€éãªåŠçã«ã¹ãããã¢ããããŠããã®ãè¯ãã§ããããå ¬åŒããã¥ã¡ã³ããã³ãã¥ãã㣠(Stack Overflow ãªã©) ãåèã«ããªãããpywinauto ã®å¯èœæ§ãæ¢æ±ããŠã¿ãŠãã ããïŒ
Happy Automating with pywinauto! ððð»
ã³ã¡ã³ã