ページからデータをとりだそうとするとき、詳細な情報が書かれているページは別に用意されていて、もとのページと詳細ページのデータを混ぜ合わせないと全部のデータが得られないことがあります。
例としてTwitterが挙げられます。
タイムラインのページでは、発言が長い時は発言の末尾が省略されて ... になるため、発言の個別ページにいって発言全体を取得する必要があります(と思って今確認したら、今は長くても発言全体が表示されるようになってました...)。
以前に作ったWeb::Scraperのjavascriptバージョンwebscraper.jsはひとつのページからしかデータが取れなかったので、複数のページからもデータが取れるもの急いで作りました。
Firefoxであればブックマークレットから呼び出したり、Firebugコンソールで使えます。
make_deferred_document(document, {
paragraph: 'id("content")//tr',
data: {
name: './/a[@class="url"]/img/@alt',
id: './/td[@class="content"]/strong/a',
},
subRequest: {
url: './/a[@class="url"]/@href',
paragraph: '.',
data: {
bio: './/span[@class="bio"]',
url: './/div[@class="user_icon"]/a/@href'
}
}
} ).next( extractor ).next( function (data) {
console.log(data);
} )
こんなかんじで取り出す部分を指定して使います。
そうすると
bio(自己紹介のところです)部分といっしょに、ユーザのIDと表示名を取得することができます。と、ここまでは一見よさそうなんですけど....

id,nameと個別ページから取り出しているbioのデータとが同じ人のものではなくほかの人のものが混ざっている状態なのでした....
途中まで、時間的都合で再起的にたどるのはあきらめて2段階しかたどれない実装でいいやと思って書いていて、そのときはちゃんと動いてたのですが、やっぱりルールに従って何段階でもたどれるようにしたいと思って書き直したのが失敗でした。
こういう、ほかのページをXMLHttpRequestで取得して全部のページのロードと処理が終わってから非同期でなにかを処理するときにはJSDeferredが便利です。MochiKitのDeferredも同じように使えます(がJSDeferredに比べてファイルのサイズが大きいのでちょっとしたのが書きたい時にはちょっとおおげさなかんじがします)。
javascriptで複数ページからデータを集めてくるのは、ずっとまえから欲しかったので再度挑戦したいと思います....
トラックバック元エントリにこのエントリへのリンクがない場合はトラックバックを受け付けません。
http://labs.gmo.jp/mt/mt-tb.cgi/225
comments