忙しいけど、どうしても単調なことをしないといけない。
例えば、とあるツールに大量のデータを読み込ませて処理をさせないといけないけど、そのツールが正しくGUIツールで、いちいち確認ダイアログとか押さないと次に進まない!!!って言うようなやつ。
平たく言えば、そういうのはそもそも設計的に想定していなかった用途だけど、それしか使うものがないから仕方なく使うけど、大量データを食わせて動作させると発狂しそうな作業になったりする。
僕もたまたまそういう作業にぶち当たり、これはなんとかならんか・・・と思いたち、色々調べていると、以下の記事を拝見しました。
なるほど、PyAutoGuiってので大変便利なことが出来るわけか。よし、やってみよう。
と言うことで、スクリプトを作成してみました。
上記記事をベースにしながら、
How to emulate button click with Python and winapi?
これも参考にして、ボタンを取得する動作を実装した。
また、僕はVisual Studioコードでデバッグしながら実際の処理も動かすモノグサなんだけれど、clickメソッドが実行されてるのに対象ウィンドウのボタンが押されないので何かと思って調べてみると、
Application not responding to Windows API events?にある通り、管理者権限でないと動作しないみたいだった。
VS Codeを管理者権限で起動すると、うまく動作した。
さて、スクリプトは以下の通りとなった。
ちなみに当方の動作環境は以下の通り。
- Python 3.7.0
- Windows7 SP1 64bit
# -*- coding: utf-8 -*-
import time
import win32gui
import win32api
import pyautogui
count = 0
child_list = []
#指定されたボタン名のハンドルをリストに追加
def add_to_list(hwnd, param):
if win32gui.GetWindowText(hwnd) == "ボタン名":
child_list.append(hwnd)
if __name__ == "__main__":
#ずっと動かすので無限ループ
while True:
#ループするたびに空にしておく。
#5秒ごとに実行する。
child_list = []
time.sleep(5)
#対象ウィンドウを取得。第二引数にウィンドウタイトルを指定。
hwnd = win32gui.FindWindow(None, "対象ウィンドウタイトル")
if hwnd <= 0:
continue
#ハンドルがある場合、子要素をすべて列挙してリストに突っ込む。
win32gui.EnumChildWindows(hwnd,add_to_list,None)
if len(child_list) == 0:
continue
if child_list[0] == 0:
continue
#対象のハンドルが取得出来たと言うことは、指定された名前のボタンがあったと言うこと。
#そいつの座標を取得する。
rect = win32gui.GetWindowRect(child_list[0])
x = (rect[0]+rect[2])/2
y = (rect[1]+rect[3])/2
pyautogui.moveTo(x,y,duration=1)
pyautogui.click(x,y,button='left')
count=count+1
print(str(count)+"回終了")
これを実行している間は、定期的にカーソルが動くので、放置プレイがおすすめ。
pyautogui.moveTo(x,y,duration=1)
の部分をコメントアウトするとカーソルが移動する動作はなくなるが、瞬時にカーソルが移動するようになるので、いずれにせよあまり向かない。
また、クリックする性質から、対象ウィンドウは見えてなきゃいけない。
諸々の制約はあるけど、それを乗り越えれば、人間がトイレに行っている間もマシンは文句も言わず黙々と仕事をしてくれているはずだ。