※この記事は7年以上前の記事です。
現在は状況が異なる可能性がありますのでご注意ください。
どうも、最近自動車学校通い始めました。
十年間避け続けてきたが、もう取らざるをえなくなった。(歳がばれる)
さて、表記の件、まずはJXAってなんぞやっていうと、
AppleのOS操作自動化スクリプト、AppleScriptの、JavaScript(以下JS)版である。
主に大量のバッチ操作などをする時に使用するものだ。
覚えれば超便利。
うちの会社では、WSH(Windows Script Host)を使って、お客様からのデータを加工したりしている(もちろんここでは詳しく書けない)ので、
Appleにもあるだろなーと、存在自体は知っていたが、別に手をだしていなかった。
だが、最近、ある人から頼まれて調べてたのだが、
これはとんでもない仕組みだと実感した。
ましてや、最近のOSだと、JSでできるときたではないか!
JSはもう大好きなんで、これはやってみるしかない!
ってわけで、ここ何日かはこれにハマってましたw
前置き長いってな。
では、表記の、自動で、ブラウザを立ち上げ、twitterにログインってのをやってみようかと。
Macのスクリプトエディタを立ち上げ、下記コードを書いて実行する。
// Google Chromeを定義 var app = Application("Google Chrome"); app.includeStandardAdditions = true; var windowChrome = null, tabFirst = null; if (app.windows.length === 0) { app.Window().make(); } windowChrome = app.windows[0]; tabFirst = windowChrome.tabs[0]; tabFirst.url = "https://twitter.com/?lang=ja"; // Chromeをアクティブにする app.activate(); // ブラウザ上で実行させる関数を定義 var runFunction = function(){ var loginBtn = document.getElementsByClassName('StreamsHero-buttonContainer').item(0).lastElementChild; loginBtn.click(); var formDom = document.getElementsByClassName('LoginDialog-form').item(0).firstElementChild; var inputDivsUser = document.getElementsByClassName('LoginForm-username'); var inputDivsPass = document.getElementsByClassName('LoginForm-password'); for (var iU = 0; iU < inputDivsUser.length; iU++) { inputDivsUser.item(iU).firstElementChild.value = 'ログインアドレス'; } for (var iP = 0; iP < inputDivsPass.length; iP++) { inputDivsPass.item(iP).firstElementChild.value = 'パスワード'; } formDom.submit(); }; // 関数を一行テキストに var runFunctionStr = runFunction.toString(); runFunctionStr = runFunctionStr.replace(/t/g, ""); runFunctionStr = runFunctionStr.replace(/n/g, ""); // ページが完全に読み込まれるまで、delayを繰り返す while (tabFirst.loading()) { delay(0.5); if (!tabFirst.loading()) { formSubmitFlg = app.execute(tabFirst, {javascript: "(" + runFunctionStr + ")(); 'true'"}); break; } }
と、こうやって、あとはスクリプトエディタの実行ボタン(再生マークっぽいの)を押すと、
Google Chrome(以下Chrome)が立ち上がって、twitterにログインできたはずだ。
さて、今回は、言語も言語なので、解説していこう。
var app = Application("Google Chrome"); app.includeStandardAdditions = true; var windowChrome = null, tabFirst = null;
一行目、まずは、当然のことながら、Chromeを取得。
二行目はよくわかんないです。おまじないみたいなもんかも。
んで、4、5行目は、後にオブジェクトを使いやすくするために、変数の宣言を行っている。
if (app.windows.length === 0) { app.Window().make(); } windowChrome = app.windows[0]; tabFirst = windowChrome.tabs[0]; tabFirst.url = "https://twitter.com/?lang=ja"; app.activate();
1~3行目は、Chromeのウィンドウが出てなかったら、ウィンドウを追加する、としている。
(Macならではだね)
5、6行目で、ウィンドウ、最初のタブ、を変数に入れている。
7行目の時点で、twitterにアクセスがされる。
最後の行は、Chromeを最前面に移動する(Chromeウィンドウをクリックして、一番上に出した状態とだいたい同じ)。
// ブラウザ上で実行させる関数を定義 var runFunction = function(){ var loginBtn = document.getElementsByClassName('StreamsHero-buttonContainer').item(0).lastElementChild; loginBtn.click(); var formDom = document.getElementsByClassName('LoginDialog-form').item(0).firstElementChild; var inputDivsUser = document.getElementsByClassName('LoginForm-username'); var inputDivsPass = document.getElementsByClassName('LoginForm-password'); for (var iU = 0; iU < inputDivsUser.length; iU++) { inputDivsUser.item(iU).firstElementChild.value = 'ログインアドレス'; } for (var iP = 0; iP < inputDivsPass.length; iP++) { inputDivsPass.item(iP).firstElementChild.value = 'パスワード'; } formDom.submit(); }; // 関数を一行テキストに var runFunctionStr = runFunction.toString(); runFunctionStr = runFunctionStr.replace(/t/g, ""); runFunctionStr = runFunctionStr.replace(/n/g, "");
さてここからが少し難しくなってくる。
これは、コメントにもある通り、ブラウザ上で実行させたいJSを記述している。
要はURLにjavascript: hoge();
みたいにするあれである。
やっていることとしては、twitterページ上で、
ログインボタンをクリック、
メールアドレス、パスワードのinputに文字列を挿入、
ログインフォーム送信
みたいな流れを書いてる。
最後の三行は、ブラウザのURLにスクリプトを打ち込むために、関数自体を一行テキストに変換している。
(正規表現に関しては、一発でやる方法があるはずだが、めんどいのでゴリ押した)
さて、ここからが大事、というか本題。
// ページが完全に読み込まれるまで、delayを繰り返す while (tabFirst.loading()) { delay(0.5); if (!tabFirst.loading()) { formSubmitFlg = app.execute(tabFirst, {javascript: "(" + runFunctionStr + ")(); 'true'"}); break; } }
Webページの読み込み完了してから、次の関数を実行するという工程だ。
まず、二行目からwhileしてるのがみそ。
tabFirstには、ブラウザのタブデータが入っているが、
そのloadingメソッドを実行すると、ページの読み込み状態が、Boolean値で返ってくる。
読み込み途中が、true、読み込み完了がfalse。
これを利用し、読み込み途中の間は、whileで、処理を待たせるメソッド(delay(second))を実行し続ける。
これによって、ページを読み込んで、DOMを形成した後に、続きを実行ってできるわけ。
んで、lodaingがfalse(読み込み完了)になったら、次の関数を実行してる。
なぜ、こんなまどろっこしいことをしているかというと、
ブラウザ上の、URLからのJS実行(javascript: hogehoge();)だと、
タイマーメソッド(setTimeout、setInterval)が使えないことと、
読み込み後に実行される、window.onloadは、
ページが読み込まれた後に実行する、URLからのJS実行では、走らない、からだ。
以上二点から、JXA上で読み込み感知をする必要があった。
ほんと今回は勉強になったし、
まさかここまでやれるもんだとは思わなかった。
OSスクリプト恐るべし。
これ、今回のログインだけだったら、大したなんもできないけど、
例えば、Gigaファイル便とかにファイルをアップロード、
URL発行されたら、それをメールで送信、なんてできたら、
仕事にも十分使えるでしょう。
間違いなく、それできますよ、JXA(というかAppleScript)
にしても、JS流行りまくりだねw
AdobeのバッチスクリプトもJSベースじゃないですか。
Cなみに派生言語でてるんじゃないべか。
やれるようになっててよかったよほんに・・・。
コメントする