node.jsでhello world気分でスクレイピング2
前回は、環境構築+JQueryを使うための調べもので終わってしまいましたが、今回は、いろんなエンコードのサイトを取得して、utf-8に変換し、JQueryを使えるところまで作ります。
スクレイピングするにもまずはスタートラインにたたないとね。
処理を作る前に、iconvが必要なので、まずはその取得からです。
iconvのインストール
昔は、npm未対応だったみたいですが、現在はnpmに対応しているようです。
以下のコマンドでインストールできます。
npm install iconv-jp
自分は、これであっさり使えるようになりました(コンパイルしてたから、もしかしたら上手く動かない場合もあるかも)。
いろんなエンコードのサイトを取得して、utf-8に変換する処理
node.jsとjQueryでスクレイピングするウェブアプリの作り方 のコードをベースに不要なところを削って、v0.6.7のドキュメントみて、htmlの取得部分を書き換えました。
あとは、以下のサイトを参考にリダイレクトできるようにしました(短縮URLぐらいは処理できるようにした方がいいかと思って)。
そんな感じで作ったのが以下のコード。
// httpGet.js var http = require('http'), https = require('https'), iconv = require('iconv').Iconv, url = require('url'); // Bufferを連結する function concatBuffer(src1 /* , src2, ... */) { var i, buf, start; var len = 0; for (i = 0; i < arguments.length; ++i) { len += arguments[i].length; } buf = new Buffer(len); start = 0; for (i = 0; i < arguments.length; ++i) { var chunk = arguments[i]; chunk.copy(buf, start, 0); start += chunk.length; } return buf; } // HTTPレスポンスとBufferからエンコーディングを検出し // レスポンスボディを文字列で返す function convertCharset(response, buf) { var charset = null; var content_type = response.headers['content-type']; if (content_type) { re = content_type.match(/\bcharset=([\w\-]+)\b/i); if (re) { charset = re[1]; } } if (!charset) { var bin = buf.toString('binary'); re = bin.match(/<meta\b[^>]*charset=([\w\-]+)/i); if (re) { charset = re[1]; } else { charset = 'utf-8'; } } switch (charset) { case 'ascii': case 'utf-8': return buf.toString(charset); break; default: var ic = new iconv(charset, 'utf-8'); var buf2 = ic.convert(buf); return buf2.toString('utf8'); break; } } exports.httpGet = function(targetUrl, callback) { var callee = arguments.callee; var chunks = []; var opts = url.parse(targetUrl); var req = (opts.protocol.match(/https/) ? https : http); req.get(opts, function(res) { if(res.statusCode == 301 ||res.statusCode == 302) { callee(res.headers.location, callback); } else if(res.statusCode == 200) { res.on('data', function (chunk) { chunks.push(chunk); }); res.on('end', function () { var buf = concatBuffer.apply({}, chunks); delete(chunks); var body = convertCharset(res, buf); callback(null, body); }); } else { callback(new Error('statusCode is ' + res.statusCode),null); } res.on('close', function (err) { delete(chunks); callback(err, null); }); }); }
いろんなエンコードのサイトを取得して、utf-8に変換して、JQueryをつかるようにする処理
htmlを取得できるようになったので、次はJQueryです。
httpGet.jsを読み込んで、JQueryを使えるようにする感じにしました。
// httpGetWithJquery.js // jsdomとjQueryのラッパー var jsdom = require('jsdom/lib/jsdom'), httpget = require('httpGet'); // URLからリソースを読み込みjQueryを追加する exports.getWithJqeruy = function(targetUrl,jquery_js, callback) { httpget.httpGet(targetUrl , function(err, body) { if (err) { if (callback) { callback(err,null,null); } else { throw err; } } var options = {}; options.features = {}; options.features.FetchExternalResources = false; options.features.ProcessExternalResources = false; var window = jsdom.jsdom(body, null, options).createWindow(); jsdom.jQueryify(window, jquery_js, function(window, $) { // callbackを呼び出す if (callback) { callback(null, window, $); } }); }); }
サイトを取得して、utf-8に変換してみる(動作確認)
動作確認に以下のようなコードを作成。
#!/usr/bin/env node // clientTesthttpGet.js httpGet = require('httpGet'); if (process.argv.length <= 2) { console.log('Usage: node clientTesthttpGet.js [url]'); process.exit(1); } process.argv.forEach(function(val, index, array) { if (index >= 2) { httpGet.httpGet(val , function(err, body) { if (err) { console.log(err); } console.log(body); }); } });
以下のようにターミナルで実行します。
node clientTesthttpGet.js [取得したいサイトのurl]
サイトを取得して、utf-8に変換し、JQueryをつかるようにしてみる(動作確認)
で、やっと目標だったJQueryを使ってみます。
動作確認用に、selectorを使ってテキストを取得する処理を作成。
#!/usr/bin/env node // clientTesthttpGetWithJquery.js var httpGet = require('httpGetWithJquery'); var jquery_js = 'https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js'; if (process.argv.length <= 2) { console.log('Usage: node clientTesthttpGet.js [url]'); process.exit(1); } process.argv.forEach(function(val, index, array) { if (index >= 2) { httpGet.getWithJqeruy(val, jquery_js, function(err, window, $, body) { if (err) { console.log(err); } console.log($('.hatena-moduletitle').text()); }); } });
以下のようにターミナルで実行します。
node clientTesthttpGetWithJquery.js [はてなブログのurl]
軽くためしてみましたが、きちんとselectorが機能してブログのタイトル取得できました。
これで、スクレイピングのするための準備はできましたね。
JQueryの力で、ごにょごにょすればスクレイピングし放題です。
まあ、JQueryでごにょごにょできればだけど(笑)。