PhantomJSを使って色々試してみる

  • 116
    いいね
  • 0
    コメント

PhantomJSとは

HP: PhantomJS
参考までに: GoogleとAppleが争う「WebKit」ってどうして重要?

一言で言うと、WebkitベースのHeadlessブラウザ。Webkitとは主にWebブラウザーで用いられているレンダリングエンジンのこと。PhantomJSはwebkitにbuilt-inされているJavaScriptCore (safariとかもこれを使っている) というjavascriptエンジンを採用している。スクレイピングやスクリーンキャプチャなどにも活用可能。

PhantomJSに出会うまでの経緯

Python3.4でスクレイピングを試していたらJavaScriptのレンダリングがかかっているサイトにぶつかった。PythonでさくっとWebスクレイピングする (JavaScript読み込みにも対応しつつ)というサイトを参考に辿って行くことに。。

Installation

ということで実際にインストール開始。
$ brew install phantomjs

Experiment #0

ネット上に公開されているQuick Startを参考に色々試してみることにする。基本的にはJavascript言語を使っていく。

Experiment #1 Hello, World!

terminal上でプロジェクトを行うディレクトリへ移動(もしくはmkdir ファイル名)。プロジェクトディレクトリ内でtouch hello.jsでファイルを作成しopen hello.jsで肉付け開始。

hello.js
console.log('Hello, World!');
phantom.exit();

terminal上でphantomjs hello.jsを実行するとHello, World!と返ってくる。最初のラインであるconsole.logという命令によりHello, world!というストリングをターミナルに投げ込む。投げ込んだ情報をphantom.exit()というコマンドによって実際に実行される。ちなみにphantom.exit()コマンドを書かないとコードが処理されない。

Experiment #2 Page Loading

PhantomJSを用いて任意のウェブページをオブジェクトを作成し、そのウェブページの読み込み、解析、生成を行うことが可能。

page_loading.js
//headlessブラウザを作る
var page = require('webpage').create();

//指定したURLを開く
page.open('https://google.com', function(status) {
  console.log("Status: " + status);
  if(status === "success") {
    //screen capture
    page.render('google.png');
  }
  phantom.exit();
});

成功するとStatus: successと表示され表示され、作業ディレクトリ内にgoogleのスクリーンキャプチャがあるはず。
他にもページを読み込む速度などを測定できたりするらしい。例えばhttp://www.google.comへのページの読み込み速度を知りたい場合、

loadspeed.js
var page = require('webpage').create(),
  system = require('system'),
  t, address;

//<>内に指定のURLを入れる
if (system.args.length === 1) {
  console.log('Usage: loadspeed.js <http://www.google.com>');
  phantom.exit();
}

t = Date.now();
address = system.args[1];
page.open(address, function(status) {
  if (status !== 'success') {
    console.log('FAIL to load the address');
  } else {
    t = Date.now() - t;
    console.log('Loading ' + system.args[1]);
    console.log('Loading time ' + t + ' msec');
  }
  phantom.exit();
});

phantomjs loadspeed.js http://www.google.comで実行すると、Loading http://www.google.com
Loading time 698 msec
といった実行結果が表示される。

Experiment #3 Code Evaluation

基本的にはevaluate()関数を使ってウェブ上のJavaScriptのデータを取得することができる。例えばwebページでのタイトルを取得したいなんて時は、

// headlessブラウザを作成
var page = require('webpage').create();

//URLを開く
page.open('http://www.google.com', function(status) {
  //ブラウザ内でJSを介してデータを取得  
  var title = page.evaluate(function() {
    return document.title;
  });
  console.log('Page title is ' + title);
  phantom.exit();
});

terminal上で実行するとPage title is Googleと表示される。

Supplemental tryout

PhantomJsを使ってgoogle mapをベースとした運転案内までできちゃう。

direction.js
// Get driving direction using Google Directions API.

var page = require('webpage').create(),
    system = require('system'),
    origin, dest, steps;

if (system.args.length < 3) {
    console.log('Usage: direction.js origin destination');
    console.log('Example: direction.js "San Diego" "Palo Alto"');
    phantom.exit(1);
} else {
    origin = system.args[1];
    dest = system.args[2];
    page.open(encodeURI('http://maps.googleapis.com/maps/api/directions/xml?origin=' + origin +
                '&destination=' + dest + '&units=imperial&mode=driving&sensor=false'), function (status) {
        if (status !== 'success') {
            console.log('Unable to access network');
        } else {
            steps = page.content.match(/<html_instructions>(.*)<\/html_instructions>/ig);
            if (steps == null) {
                console.log('No data available for ' + origin + ' to ' + dest);
            } else {
                steps.forEach(function (ins) {
                    ins = ins.replace(/\&lt;/ig, '<').replace(/\&gt;/ig, '>');
                    ins = ins.replace(/\<div/ig, '\n<div');
                    ins = ins.replace(/<.*?>/g, '');
                    console.log(ins);
                });
                console.log('');
                console.log(page.content.match(/<copyrights>.*<\/copyrights>/ig).join('').replace(/<.*?>/g, ''));
            }
        }
        phantom.exit();
    });
}

を適当なディレクトリに投げ込んでおき、terminal上でphantomjs direction.js 出発地 到着地で実行。試しにphantomjs direction.js Tokyo Osakaで実行したところ、

Head south
Turn right at 都庁南(交差点) toward 都道431号線
At 角筈区民センター前(交差点), continue onto 都道431号線
Turn left at 西新宿四丁目(交差点) onto 山手通り/都道317号線
Continue straight to stay on 山手通り/都道317号線
Take the ramp on the right to 首都高速中央環状線
Toll road
Continue onto Exit 初台南料金所
Toll road
Merge onto 首都高速中央環状線
Toll road
Take exit 大橋JCT on the right toward 東名・都心環状
Toll road
Keep left at the fork, follow signs for 東名 and merge onto 首都高速3号渋谷線
Toll road
Keep right to continue on 東名高速道路
Toll road
Keep right at the fork to stay on 東名高速道路, follow signs for 右ルート・静岡・御殿場
Toll road
Take exit 御殿場JCT toward 新東名・静岡・名古屋
Toll road
Continue onto 新東名高速道路
Toll road
Continue onto Exit 浜松いなさJCT
Toll road
Keep right at the fork, follow signs for 東名・東京・名古屋 and merge onto 新東名高速道路
Toll road
Take exit 三ヶ日JCT on the right toward 東名・名古屋
Toll road
Merge onto 東名高速道路
Toll road
Take exit 豊田JCT toward 東海環状・伊勢湾岸道・豊田東出口・土岐JCT・四日市・新名神
Toll road
Keep right at the fork, follow signs for 伊勢湾岸道・四日市・新名神 and merge onto 伊勢湾岸自動車道
Toll road
Take exit 高速飛島IC on the right toward 伊勢湾岸自動車道
Toll road
Continue onto 伊勢湾岸自動車道
Toll road
Take exit 四日市JCT on the right toward 東名阪道・大阪・伊勢道
Toll road
Merge onto 東名阪自動車道
Toll road
Take exit 亀山JCT toward 新名神・京都・大阪
Toll road
Continue onto 新名神高速道路
Toll road
Take exit 草津JCT toward 草津PA・名神・京滋・京都・大阪
Toll road
Keep right at the fork to continue on Exit 草津PA, follow signs for 名神 and merge onto 名神高速道路
Toll road
Keep right at the fork to stay on 名神高速道路, follow signs for 右ルート
Toll road
Take exit 豊中IC toward 阪神高速・豊中出口・大阪市内
Toll road
Keep left at the fork, follow signs for 大阪市内・一般道出口・阪神高速
Toll road
Keep right at the fork to continue on Exit 高速豊中IC, follow signs for 阪神高速
Toll road
Continue onto Exit 名神阪神料金同時徴収料金所
Toll road
Merge onto 阪神高速11号池田線
Toll road
Merge onto 阪神高速1号環状線
Toll road
Take exit 都市高北浜 toward 北浜出口
Partial toll road
Turn right at 菅原町西(交差点) onto 堺筋
Slight right to stay on 堺筋
Slight right onto 天神橋筋
Turn right at 天神橋(交差点) onto 土佐堀通/府道168号線
Turn right at 北浜2(交差点) toward 中之島通
Turn is not allowed 8:00 AM – 8:00 PM
Turn left toward 中之島通
Turn left onto 中之島通
Destination will be on the left

正確さは別としてとりあえず動く模様。PhantomJSだけでも色んなことが試せることが判明。
参考: direction.js