ajaxなページもクローラーに読ませたいですよね。
そこでPhantomJS, CasperJS, SpookyJSです。
簡単に説明するとこんな感じ
PhantomJS
コマンドラインから使える画面がないwebkitブラウザ
CasperJS
PhantomJSのユーティリティ、PhantomJSをもっと便利に使えるようにするやつ
SpookyJS
casperJSをNodejsから使えるようにするやつ
こういうことをしたい
クローラーがアクセスしてきた時だけ、アクセスしたURLをSpookyJSサーバーに投げて、SpookyJSがそのURLにアクセスし、DOMを取得してからクローラーに返すってことをしたらよさそうです。
SpookyJSをインスコ
SpookyJSはもちろんphantomJSとcasperJSに依存してるので、まずはこの2つをグローバルに入れる必要があります。
npm install phantomjs -g npm install casperjs -g
必ず -g オプション!
次にプロジェクトのディレクトリで
npm install spooky
これしたら、OK
express用サンプル
ajaxの部分が全部読み込まれましたよーっていう判断をどうやってしようかなーって思って、
今回は「js-spooky-complate」ってclassが読み込まれたら、その時点のDOMを返すようにしようと思います。
もし、そのクラスがなかった場合、404を返すようにします。
spookyJSはデフォルトで8081ポートを使うので、expressとのバッティングに注意
var Spooky = require('spooky'); exports.index = function(req, res){ var url = req.param('u'); var spooky = new Spooky({ child: { transport: 'http' }, casper: { logLevel: 'error', verbose: true, waitTimeout : 3000 } }, function (err) { spooky.start(url); spooky.waitFor(function check() { return this.evaluate(function() { return document.querySelectorAll('.js-spooky-complate').length >= 1; }); }, function then() { this.emit('complate', this.getHTML()); this.exit(); }, function timeout() { this.emit('timeout', this.getHTML()); this.exit(); }); spooky.run(); }); spooky.on('error', function (e, stack) { res.send(404); spooky.removeAllListeners(); this.exit(); }); spooky.on('timeout', function (e, stack) { res.send(404); spooky.removeAllListeners(); this.exit(); }); spooky.on('complate', function ( html ) { res.send( html, { 'Content-Type': 'text/html' }, 200); spooky.removeAllListeners(); this.exit(); }); }
(ホントは new Spookyをexports.indexの外に出したかったけど、うまくいかなかった、、、)
spookyはcasperをラップしてるだけっぽいので、casperjsのコマンドは全部使えます。
20行目のspooky.waitForの中で、js-spooky-complateが読み込まれるまでwaitしています。
デフォルトの待ち時間は5000ms ですが、上記のように「waitTimeout : 3000」を書くと3秒になります。
指定秒数内で js-spooky-complate が読み込まれた場合、spooky.waitForで, function then() に行き、クラスがなくて3秒たってしまった場合、function timeout() が呼ばれます。
クラス指定じゃなくて、強制的に数秒待つ場合
ajaxを多用してるページなどで、特定のクラスを読み込んだら完了っていう判断をしづらい場合、強制的にクローラーからのアクセスは数秒待ってから出力って事もできます。
上記のソースの spooky.waitForの部分を以下に置き換えます。
spooky.wait(2000, function() {}); spooky.then(function () { this.emit('complate', this.getHTML()); this.exit(); });
これだと、強制的に2秒待ってから出力するようになります。
こんな感じで、ajaxページもクローリングさせることができます。
あとは一番上の図のwebサーバーで、spookyJSからの結果をmemcacheに突っ込んどいたりして、キャッシュを効かせるとなおいいかなーって思います。