こんにちは、技術研究所の「むらたん」です。
この記事は 『CRESCO Advent Calendar 2017』 3日目の記事です。
ロボットを使って業務を自動化するRPA(Robotic Process Automation)が注目されています。
ロボットを使うメリットはあちこちで語られているので詳細は割愛しますが、自動化への期待はIT業界でも高く、苦行のようなテスト実施の自動化はプログラマの夢と希望であったりします。
Webブラウザをスクリプトで操作する「Selenium」というオープンソースのライブラリがあります。ブラウザの起動、指定されたURLの表示、入力値の設定、ボタンアクション、画面イメージの保存など、ブラウザで行う操作をプログラミングして実行できます。スクリプトで記述できることは何でも出来るので、Webシステムのテスト自動化のデファクトスタンダードになりつつあります。
この考え方を流用して、iOSやAndroidのアプリケーションを操作する「Appium」が登場しました。と、歴史を語りだすと止まらなくなるので、そろそろ本題です。
MicrosoftさんのGithub公式アカウントには「Windows Application Driver」が公開されており、Appiumで「Windowsアプリケーション」が操作できます。
!?
これ、Windowsパソコンを操作できるってことは、Webアプリだろうが、Excelだろうが、何でもスクリプトで操作できる最強ツールでではなかろうか。
でも、操作するためのスクリプトを書くのも辛いという方もいらっしゃると思うので、今回は実行環境の構築もプログラミングも簡単な「Python」で行います。
Selenium/Appium、Pythonを知らない方にも実践していただけるよう、細かく説明していきます。
もの | 用途 | 特筆事項 | 入手先 |
---|---|---|---|
Windows10のパソコン | 諸々の作業環境です。 | セットアップ時にはインターネットへの接続が必要になります。 | おまかせします |
エディタ | スクリプトの作成環境です。 | 今回はVisual Studio Code(VSCode)を利用します。 | こちらから |
Python | スクリプトの実行環境です。 | 今回は3.6.3を利用します。 | こちらから |
Windows Application Driver | スクリプトからの指示を受けるサーバ機能(以下 ドライバ)です。 | こちらから | |
Windows SDK | アプリケーションの解析に使うinspect.exeをインストールします。 | スクリプトの実行自体では使用しません。 | こちらから |
らくらく自動化の手順は以下のとおりです。
- 全てのアプリケーションをデフォルト設定のままインストールします。
- スタートボタンを押し、歯車ボタンを押して、「Windowsの設定」を開きます。
- 更新とセキュリティを押し、左メニューの開発者向けを押します。
- 開発者向け機能を使う で「開発者モード」に設定します。
必要に応じて、Pythonやスクリプトがドライバに接続できるよう、プロキシやファイアウォールの設定をしてください。
以下を環境変数に設定します。
項目 | 値 | 説明 |
---|---|---|
http_proxy | http://USERNAME:PASSWD@DOMAIN:PORT/ | USERNAME:プロキシユーザ名、PASSWD:プロキシユーザパスワード、DOMAIN:プロキシサーバ・ドメイン、PORT:接続ポート番号 |
no_proxy | HOST(,…) | HOST:除外ホスト、複数指定はカンマ区切りで指定する |
紹介する手順はローカルPC上で稼働するドライバに接続する手順のため特別な設定は不要ですが、ローカルPC以外でドライバを使用する時は、外部からの接続を許可してください。
- コントロールパネル>システムとセキュリティ>Windowsファイアウォールを選択し、画面左メニューの詳細設定を開く
- セキュリティが強化されたWindowsファイアウォールで受信の規則を開く
- ポートを選択して、次へ
- TCPを選択し、特定のローカルポートで「4723」を指定して、次へ
- 接続を許可するを選択して、次へ
- プロファイルで、全てチェックして、次へ
- 適当な名前を付けて、完了
pipコマンドでAppium関連のライブラリを導入するため、コマンドプロンプトで以下を実行します。
pip install robotframework-appiumlibrary |
以下のスクリプトはメモ帳でPythonスクリプトを生成後、コマンドプロンプトを起動してスクリプトを実行し、最後にスクリプト自身を消すというものです。
こちらを元にスクリプトの書き方を説明します。ここでは、hello.pyという名前で保存します。
# hello.py |
# 説明① |
from appium import webdriver |
from selenium.webdriver.common.keys import Keys |
import time |
# 説明② |
desired_caps = {} |
desired_caps["app"] = "notepad.exe" |
# 説明③ |
driver = webdriver.Remote( |
command_executor='http://127.0.0.1:4723', |
desired_capabilities= desired_caps) |
# 説明④ |
notepad = driver.find_element_by_class_name('Notepad') |
notepad.send_keys('print("Hello Windows Application Driver World!")') |
notepad.find_element_by_accessibility_id('MenuBar').send_keys(Keys.ALT + "F") |
notepad.find_element_by_accessibility_id('MenuBar').send_keys(Keys.CONTROL + "S") |
# 説明⑤ |
time.sleep(1) |
# 説明⑥ |
notepad.find_element_by_accessibility_id('FileTypeControlHost').click() |
notepad.find_element_by_accessibility_id('FileTypeControlHost').send_keys(Keys.DOWN + Keys.ENTER) |
notepad.find_element_by_class_name('ComboBox').click() |
notepad.find_element_by_class_name('ComboBox').send_keys(Keys.DOWN + Keys.DOWN + Keys.DOWN + Keys.ENTER) |
notepad.find_element_by_accessibility_id('1001').send_keys("hello.py") |
notepad.find_element_by_accessibility_id('1').click() |
# 説明⑦ |
driver.quit() |
# WindowsバッチからPythonスクリプトを実行する |
desired_caps = {} |
desired_caps["app"] = "cmd.exe" |
driver = webdriver.Remote( |
command_executor='http://127.0.0.1:4723', |
desired_capabilities= desired_caps) |
driver.find_element_by_class_name('ConsoleWindowClass').send_keys('python hello.py' + Keys.ENTER) |
driver.find_element_by_class_name('ConsoleWindowClass').send_keys('del hello.py' + Keys.ENTER) |
# driver.quit() |
ここでは、Seleniumでお馴染みのWebDriver、キー操作用のKeys、Wait処理用のtime をインポートしています。
設定内容をハッシュに格納します。ここでは起動アプリケーション(メモ帳)のみを設定します。パスが通っているので実行ファイルまで指定となっていますが、フルパスを指定することもできます。
他に設定できる項目の詳細はこちらをご覧ください。
command_executorにドライバが起動しているホスト、ポートを指定します。
desired_capabilitiesに②で用意したハッシュを指定します。
このコマンドを実行すると、ドライバがアプリケーションを起動しますので、以降、ドライバに対して指示を出して、アプリケーションを操作します。
アプリケーションは複数のUIコンポーネントから作られており、「find_element(s)_by~」で操作するロケータを特定し、「send_keys()」でキー操作、「click()」でクリック動作を指示します。
説明④では、メモ帳に「print(“Hello Windows Application Driver World!”)」と入力し、ショートカットで、ファイルの保存を行おうとしています。
説明⑥では、ファイルの保存ダイアログを操作し、実際にファイルを保存します。ダイアログは表示されているときでないと、inspect.exe(後述)で解析することが出来ません。
スクリプトの操作が速すぎる時はタイムラグを置きます。
ここでは、ファイルを保存するダイアログの表示を待つため、1秒のウェイト処理を入れています。
ドライバを終了すると、アプリケーションも終了します。
ここでは、スクリプトを作成していく中で見つけたハマりどころを紹介します。
スクリプトで指定できるロケータはこちらに書かれています。
ロケータに設定する値はinspect.exeを使って解析します。(インストール先は”C:\Program Files (x86)\Windows Kits\10\bin(バージョン番号)(プロセッサ)\inspect.exe”)
例として、メモ帳で以下のように編集エリアにフォーカスが当たっているとします。
inspect.exeでは、以下のように表示され、編集エリアに関する情報がとれます。
上記リンク先のサンプルでは「//Button[0]」のように配列指定をしていますが、上手く取れませんでした。
また、指定する項目は「Any」となっていますが、ControlTypeを加工して指定するようです。
例)メモ帳のウィンドウのControlTypeは「UIA_WindowControlTypeId」ですが、「UIA_」と「ControlTypeId」を取り除いた「Window」が指定項目になります。
私はJISキーボードを使っているのですが、send_keyでキーを送る際、キーバインドがUSに変わってしまいます。
send_key(‘\’)とすると、アプリケーションでは「]」が入力されるという挙動になります。回避策が見つかっていません。。。
アプリケーションを操作する環境でWindowAppDriver.exeを起動します。(インストール先は”C:\Program Files (x86)\Windows Application Driver\WinAppDriver.exe”)
実行時引数でIPアドレスやポート番号をカスタマイズすることができますが、IPアドレスを変更する場合は、管理者モードで実行する必要があります。
pythonコマンドでスクリプトを実行します。
cd (hello.pyの保存先) |
python .\hello.py |
らくらく自動化とは言ったものの、結構手間が掛かります。とはいえ、普段の定型作業がスクリプト化できれば、きっと幸せになれるかと思いますので、ご活用ください。