JavaScript
Mac
jXA

JXAでSafari, Chrome, Firefoxを操作する際の違い

More than 1 year has passed since last update.


まとめ

Safari: Apple謹製だけど機能少ない

Chrome: なぜか異常に充実

Firefox: ほぼ何もできない


気が向いたときにちょっとずつ更新中

Safari
Chrome
Firefox

参照
Application( "Safari" )
Application( "Chrome" )
Application( "Firefox" )

ウィンドウ
(全て)
app.windows()
app.windows()
app.windows()

ウィンドウ
(最前面)
app.windows[0]
app.windows[0]
app.windows[0]

ウィンドウ
作成
app .Document().make()
app .Window().make()
-

タブ
(全て)
win.tabs()
win.tabs()
-

タブ
(表示中)
win .currentTab()
win .activeTab()
-

タブ
切り替え
win .currentTab = tab

win .activeTabIndex = index

-

URL移動
tab.url = "http://qiita.com"
tab.url = "http://qiita.com"
-

JS実行
app .doJavaScript("alert('hi.'),{in: tab})
app .execute(tab, {javascript:"alert('hi.')"})
-

ページ更新
tab.url = tab.url()
tab.reload()
-

読込中止
-
tab.stop()
-

戻る & 進む
(やろうと思えばdoJavaScriptで)
tab.goBack();
tab.goForward();
-

ブックマーク
-
参照可(長いので省略)
-

履歴
-
-
-

Chromeの新規ウィンドウ作成は戻り値でそのままWindowを得られる。

SafariはDocumentが返ってくるからURL移動したいときとか困る。

(app.Window().make()できればいいのに・・・)

Windowを得る場合は以下のようにするといいのかもしれない・・・

var Safari = Application("Safari");

var doc = Safari.Document().make();
var win = Safari.windows[doc.name()];

//URL移動
win.currentTab.url = "http://qiita.com"


使ってみる

以下の記事と同じことをするコードを書いてみました。

JXAを知らない方はこちら。


やること

下準備


  • 待ち秒数を指定 (DELAY)

  • アプリケーションの参照を取得

  • 最前面のウィンドウを取得


ループ


  • タブを切り替えてDELAY秒だけ待つ

  • ページを更新してDELAY秒だけ待つ


試すには30秒は長いので3秒にしました。


Safari


autoreload_safari.js

const DELAY = 3;

var Safari = Application("Safari");
var window = Safari.windows[0]; //最前面のウィンドウを取得

while(window.exists()) { //無限ループ (ウィンドウが開いてなければ実行しない)
window.tabs().forEach(function(tab){

// タブ切り替え
window.currentTab = tab;
delay(DELAY);

// 更新
tab.url = tab.url();
delay(DELAY);
});
};


ウィンドウから全タブを取得できます。

タブの切り替えは現在のタブ(currentTab)に任意のタブをセットすることで行います。

Safariには表示中のページを更新する関数がありません。

ページの更新は表示中のurlをタブのurlプロパティに再セットすることで可能です。

またはdoJavaScriptによってページ内でJavaScriptを実行して更新します。


JavaScriptで更新(doJavaScript関数)

Safari.doJavaScript("location.reload()", {in:tab});


doJavaScriptはページ内での実行結果を戻り値として返します。

ページから簡単に情報を得たい場合に便利かもです。

同じJavaScriptで書けますし。

メモ:

ブックマークにアクセスすることが出来ません。

ブックマークを整理するスクリプト書きたかったのに無理でした・・・。

リーディングリストに追加する機能はあるのですが、その一覧を取得する機能も無いです。

ビビりました。


Chrome


autoreload_chrome.js

const DELAY = 3;

var Chrome = Application("Google Chrome");
var window = Chrome.windows[0]; //最前面のウィンドウを取得

while(window.exists()){ //無限ループ (ウィンドウが開いてなければ実行しない)
window.tabs().forEach(function(tab, i){

// タブ切り替え
window.activeTabIndex = i + 1;
delay(DELAY);

// 更新
tab.reload();
delay(DELAY);
});
};


ウィンドウから全タブを取得できます。

タブの切り替えはウィンドウのactiveTabIndexにインデックスをセットすることで行います。

インデックスは1から始まることに注意。

タブからはインデックスを取得できません。

そのためforEachのカウンタを利用する必要があります。

アクティブなタブを取得する関数は.activeTab()です。

これは読み取り専用なのでSafariのように他のタブをセットすることはできません。

Chromeには表示中のページを更新する機能(.reload())があります。

更新キャンセルや「進む」「戻る」の機能もあります。

もちろんページ内でJavaScriptを実行することも可能です。


JavaScriptで更新(execute関数)

Chrome.execute(tab, {javascript:"location.reload()"});


Safariと同じようにexecuteもページ内での実行結果が戻り値になります。

メモ:

今回のブラウザの中で、スクリプト向けに用意された機能はChromeがダントツで充実してました!

ブックマークにアクセスすることもできます。

ブックマークを整理するスクリプトを書くことも可能でしょう。

やってませんが。


Firefox


autoreload_firefox.js

const DELAY = 3;

var Firefox = Application("Firefox");
var window = Firefox.windows[0]; //最前面のウィンドウを取得

SystemEvents = Application("System Events");

while(window.exists()){ //無限ループ (ウィンドウが開いてなければ実行しない)

// タブ切り替え
Firefox.activate();
delay(0.3); //アクティブになるまで少し待つ
SystemEvents.keystroke("]", {using:["command down", "shift down"]});
delay(DELAY);

// 更新
Firefox.activate();
delay(0.3); //アクティブになるまで少し待つ
SystemEvents.keystroke("r", {using:"command down"});
delay(DELAY);
};


ウィンドウからタブを取得できません。

ってことはApplication.documents()でページの内容を見れるのかな?

>> Firefox = Application("Firefox")

=> Application("Firefox")
>> Firefox.windows.length
=> 10
>> Firefox.documents()
=> []
>>

!?

空の配列が返ってきました。

どうやら用語説明はテンプレそのまま使っていて、機能は何もなさそうです。多分。

ウィンドウを取得する以外、ほぼ何も出来なさそうです。

こういう場合はSystem Eventsからキーボードを押したりして操作するしかありません。

キーボードやマウス操作をする方法はこちらに書きました。

Application("Firefox")の部分を変えるだけでSafariでもChromeでも動きます。

いちいち.activate()する必要があるので他の作業中に動作させるのは無理です。

メモ:

ページの内容すら取得できないんじゃ・・・?

スクリプトで操作するなら別のブラウザを使いましょう。

追記:

windowにもdocumentプロパティがあることに気付きましたが、nullでした。

varFirefox = Application("Firefox");

Firefox.windows[0].document();
//=> undefined

Firefox.windows[0].properties();
//=> {"document":null, "closeable":true, "zoomed":true, "class":"window", "index":1, "visible":true, "name":"Yahoo! JAPAN", "modal":false, "miniaturizable":true, "titled":true, "id":6188, "miniaturized":false, "floating":false, "resizable":true, "bounds":{"x":0, "y":23, "width":1280, "height":709}, "zoomable":true}

ウィンドウからページのタイトルだけ取得できるようです。

上の例だとYahooを開いていることがnameプロパティで分かります。

ページ内容を取得する方法が存在するなら、知ってる方教えてください。


蛇足

ぜんぜん関係ないけど、Terminalでシェルスクリプトを実行するdoScriptもSafariのdoJavaScriptと同じ構文

ただし戻り値はタブの参照です。タブを指定しない場合は新しいウィンドウを開くので。


Terminal

var Terminal = Application("Terminal");

var tab = Terminal.windows[0].selectedTab(); // SafariはcurrentTab。名前統一してくれ

Terminal.doScript("echo 'hi.'", {in:tab});
var newTab = Terminal.doScript("echo 'hi new window.'");


コマンド実行の戻り値を得たい場合はdoShellScriptを使います

これはTerminalじゃなくても使えます


doShellScript

var app = Application.currentApplication();

app.includeStandardAdditions = true;

var date = app.doShellScript("date");