AppleScriptを初めて触った。専門学校の時に、このようなScriptがあると言うのは聞いていたが、触ったのは初めてだ。業務で繰り返しの作業が必要になり、なんとか作業効率化のためにFinder作業を簡単に済ませたいと思った。
何をしたいのか
したいことは、昨年と一昨年行った各プロジェクトの売上のリストをZACという管理システムからダウンロードしたいというものだ。だいたいプロジェクトの数は1年で60程度。つまり、120件ダウンロードすれば良い話だ。Scriptを組まなくても、手作業でもできるが、せっかくなので勉強がてら組んでみようと思った。
以前はwindowsを業務で使用していたので、VBAからIEを動かす処理を書いていた。なんとなくイメージはできていた。
作業内容
作業手順はいたって簡単だ。オロ社から出ているZACという業務管理システムにアクセスして、1年間の期間を入力し、プロジェクト番号を入力、CSVをダウンロードする。
とっかかりは意外と簡単だった。
AppleScriptでChromeを立ち上げ、URLにアクセスする、そして、ブラウザ内でJSを使って、それぞれのフォームに値を入力する。これをプロジェクト数ぶん繰り返すだけだ。
コード
tell application "Google Chrome"
tell window 1
set newTab to make new tab with properties {URL:"https://***アクセスしたいURL****"}
repeat while loading of active tab
delay 1
end repeat
tell active tab
execute javascript "var projectNum = ['0154','0900','0368','0400','0956','0957','0878','0637','0461','0923','0951','0481','0929','0591','0808','0700','0970','0715','0876','0828','0870','0820','0786','0871','0872','0873','0877','0920','0610','0647','0823','0869','0138','0775','0791','0875','0925','0881','0922','0952','0740','0868','0887','0078','0142','0150','0285','0491','0678','0038','0473','0783','0909','0914','0926','0941','0944','0389','0848','0894','0964','0682','0945','0947','0953','0954','0955','0936']"
execute javascript "document.forms['frmOutput'].elements['y_date_start'].value = '2015'"
execute javascript "document.forms['frmOutput'].elements['m_date_start'].value = '4'"
execute javascript "document.forms['frmOutput'].elements['y_date_end'].value = '2016'"
execute javascript "document.forms['frmOutput'].elements['m_date_end'].value = '3'"
execute javascript "document.forms['frmOutput'].elements['d_date_end'].value = '31'"
execute javascript "var k = 0;"
repeat 68 times
execute javascript "document.forms['frmOutput'].elements['code_project_group'].value = projectNum[k];"
execute javascript "k++;"
execute javascript "document.getElementsByTagName('input')[53].click();"
delay 2
end repeat
end tell
end tell
end tell
AppleScriptの知識ゼロの状態から書いたので、結構苦戦しました。
冒頭のChromeを立ち上げ、該当のURLにたどり着くまでは問題なくできましたが、それ以降Chrome内でJSを動かすところが非常に大変でした。
tell application "Google Chrome"
〜
end tell
あくまでも、私の解釈ですが、tell〜end tellまでが一つの塊になり、functionみたいなものでしょう。この間は、最初に定義した物に対して作業をするような感じだと思います。
なので、この冒頭の部分で「applicationのChromeに対して作業します。」と宣言している感じだと思います。
そして、Chromeの宣言の間に次のスクリプトを書きます。
ここがnew tab(新しいタブ)にURLを設定してmake(作れ)となります。
tell window 1
set newTab to make new tab with properties {URL:"https://***アクセスしたいURL****"}
〜
end tell
そして、loadingを待つことになります。
repeat while loading of active tab
delay 1
end repeat
delayがよくわからないのですが、多分、アクション時間のような気がします。つまり、ここの部分でloadingが終わるのを待っているのではと感じました。
ブラウザ内でJSを動かす
そして、ここまででZACのページをChromeで開くことができました。ZAC自体はログインが継承されるので、一度ログインしていれば別タブが開いてもログインした状態でアクセスすることができました。
tell active tab
〜
end tell
この部分がactive tabに対して処理を行うことになります。
「execute javascript」と書いてからダブルコーテーションでJSソースを囲むと、ブラウザないで通常のJSを動かすことができます。jQueryを使えればフォームに対しての処理が楽ですが、使えないので、通常のdocumentでフォームを指定してvalueを変更していきます。
最初にダウンロードしたいプロジェクトの番号を配列に入れて、それを順番に処理していこうと思いました。次に期間を入れていきます。ZACのHTMLのフォームはidが設定されておらず、nameで処理しました。このHTMLの記述が最悪でシステム会社が作るHTMLって感じが丸出しです。
うちの使っているヴァージョンのせいで今の最新のものはもっとまともなのかもしれませんが、この辺はちゃんと設計してほしいものです。
forの処理
期間フォームまでは問題なかったのですが、配列に入れた番号をプロジェクト番号をインプットするフォームに繰り返し入れて、ダウンロードしていきます。
最初は、JSのforで処理していたのですが、なかなかうまくフォームに入りませんでした。
なんとなく、処理を見ていると、JSのforが先に処理されてからfor内の次のアクションに移っている感じでした。つまり、当初は番号を入れてボタンを押して、次の番号と考えていたのですが、先に配列の番号だけがフォームに順番に記述されて、そのあとボタンが押されている状態に感じます。
多分、順番に処理しているんだと思いますが、ボタンのアクションに時間がかかりタイムラグが発生している状態です。JSで時間を待つ設定も記述したのですが、全く反応しませんでした。
そこで、思ったのが、AppleScript側で繰り返し処理を行うことです。
この発想にたどり着いたのが体感として3時間以上たった感じです。
execute javascript "var k = 0;"
repeat 68 times
execute javascript "document.forms['frmOutput'].elements['code_project_group'].value = projectNum[k];"
execute javascript "k++;"
execute javascript "document.getElementsByTagName('input')[53].click();"
delay 2
end repeat
変数kの値を作り、変数の番号としました。
そして、delayを設定しAppleScript側で待つ作業を加えました。
2つのSubmitボタン
次にハマったのがSubmitボタンです。これがZACのHTMLが最悪のところです。nameが両方ともSubmitになっているため、nameでの判定ができない状態です。そのため、ページ内のinputを取得して、個数で判定しました。これを設定するまでに体感で2時間以上かかりました。
いかにセマンティックなHTMLが重要で、エンジニアの脳が柔軟じゃないと時間短縮ができないかがわかります。
execute javascript "document.getElementsByTagName('input')[53].click();"
AppleScriptはJSでも記述できるので、言語習得が非常に楽です。それで、Macの効率化を測れるのはありがたい。この機会に繰り返し発生する処理はAppleScriptを使っていこうと思います。