Contents
WinAppDriver.exeを起動してもすぐに消えてしまう場合
Windows10の開発者モードをオンにする。設定→更新とセキュリティ→開発者向けで開発者用モードをオンにする。
WinAppDriverのdriverを取得
1 2 3 4 5 6 7 8 9 10 |
from appium import webdriver # デスクトップセッションでdriver取得 driver = webdriver.Remote( command_executor='http://127.0.0.1:4723', desired_capabilities={'app': 'Root'} ) driver.implicitly_wait(30) elem = driver.find_element_by_name('ウィンドウ名') |
スプラッシュスクリーンのあるアプリだと例外投げて死んでしまうため、デスクトップセッションでdriverをゲットしてからアプリウィンドウにアクセスするのが吉。
もちろんスプラッシュスクリーンがなければアプリ起動と同時にdriverゲットしてもいい。その場合は↑でRootをアプリの絶対パスにする。
アプリを起動する
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
import subprocess, time process = subprocess.Popen( "アプリの絶対パス", stdout=subprocess.PIPE, cwd="カレントワーキングディレクトリ" ) while True: # いじりたい構成部品が現れるまで待つ elems = self.driver.find_element_by_name('トップレベルウィンドウ名').find_elements_by_class_name('構成部品') if elems: break else: time.sleep(1) |
ウィンドウハンドルを取得する
1 2 3 4 5 6 7 8 9 10 |
import win32gui # トップレベルウィンドウのハンドル取得 parent_handle = win32gui.FindWindow('クラス名', 'ウィンドウ名') # サブレベル(?)ウィンドウのハンドル取得 handle = win32gui.FindWindowEx(parent_handle, None, 'クラス名', 'ウィンドウ名') # WinAppDriverならトップレベルウィンドウ経由じゃなくても下のレベルのウィンドウハンドルが取得できる handle = driver.find_element_by_name('ウィンドウ名').get_attribute('NativeWindowHandle') |
- FindWinow/FindWinowExのクラス名・ウィンドウ名はどちらか一方はNoneでOK(ほかのウィンドウと被りがなければ)
- FindWinowExの第一引数の親ウィンドウのハンドルは必須。
- get_attributeメソッドの戻り値は文字列なのでintにキャストしてから使う
- ウィンドウが見つからないと0を返す。
ウィンドウの座標取得
1 |
x1, y1, x2, y2 = win32gui.GetWindowRect(handle) |
トップレベルウィンドウの座標を取得すると、実際よりずれていることが多々ある。その場合、下のレベルのウィンドウの座標を取得するとぴったり合うことがよくある。
コンテキストメニューを出す
1 2 3 4 5 6 |
from selenium.webdriver.common.keys import Keys from selenium.webdriver.common.action_chains import ActionChains elem = driver.find_element_by_name('アプリ名') actions = ActionChains(driver) actions.context_click(elem).perform() |
バッチファイルから起動する
には以下のようなバッチファイル(.bat)をプログラムとおなじフォルダにつくる。
1 2 3 |
start /d "E:\App\Windows Application Driver" WinAppDriver.exe timeout /t 3 > nul python program.py |
orchis(ランチャソフト)からクリックで起動する場合は、項目の設定で作業フォルダを「参照先ファイルと同じフォルダ」にするのを忘れないようにする。
バッチファイルの3行目でプログラムを絶対パスで指定してもいいが、プログラム中からほかのファイルにアクセスしている場合、それらも絶対パスにしなければならないため面倒。
ウィンドウ名が変化する場合
たとえばタスクバーの通知領域の各アプリはボタンになっているけど、状態によってNameが変化することがある。その場合はまず通知領域のボタンを全部取得してから、条件にマッチするボタンを見つける。
1 2 3 4 5 |
def get_button(driver): parent = driver.find_element_by_name('タスク バー').find_element_by_name('ユーザーによって昇格された通知領域') buttons = parent.find_elements_by_xpath('//Button') # ボタンをすべて取得 for button in buttons: if re.search('正規表現', button.get_attribute('Name')): return button |