JXA、Webページが読み込まれたら実行(twitterにログインする)

謎のプリン語る。
プログラミングの役立つ情報とか、どうでもいい雑談とか書いてます。
一人書く人増えました。

JXA、Webページが読み込まれたら実行(twitterにログインする)

みやびプリン 500 316

500 320

JXA、Webページが読み込まれたら実行(twitterにログインする) - サムネイル

※この記事は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なみに派生言語でてるんじゃないべか。
やれるようになっててよかったよほんに・・・。

格安でソーシャルゲームイラストを構築します【EAGLEGRAPHICS】 - メイン

トラックバック(0)

トラックバックURL:

コメントする

ページトップへ戻る