最近、以前Pythonで実装したクローラーをnode.jsに移行しようとしています。将来的にpuppeteerを使ったスクレイピングが必要になったときにnode.jsで詰まりたくないのと、Promise
やasync/await
を使ったプログラミングのサンプルとして遊んでみたかったのがその理由です。
ただ、文字コードの判定と変換の実装で多少詰まってしまったのでメモ書きしておきます。
const rp = require('request-promise'); const cheerio = require('cheerio'); const jschardet = require('jschardet'); const iconv = require('iconv-lite'); const sampleFetch = async (url) => { return await rp.get({ "uri": url, "followAllRedirects": true, // encodingにnullを指定することで文字列ではなくBufferとして読み込む "encoding": null, "transform": (body, response, _) => { // jschardetで文字コードを推定し、iconvで変換する const encoding = jschardet.detect(body).encoding; const decoded = iconv.decode(body, enc); // cheerioでタイトルを取得する const $ = cheerio.load(decoded); return $('title').text().trim(); }, "headers": { 'User-Agent': 'Sample-Crawler' } }); }
これらのページを参考にしました。
テストしてみましょう。
また、個人的に使い慣れているRuby
のRSpec
に近い使い勝手の、jasmine
というライブラリを利用しています。it
のコールバックにdone
が入り、それを非同期処理のテストも簡単に書けるようです。
rewire
というライブラリを使うことで、exportしていないメソッドもテストできます。
const rewire = require('rewire'); const samplecode = rewire('./samplecode'); describe("sampleFetchのテスト", () => { const sampleFetch = samplecode.__get__("sampleFetch"); it("UTF-8のページのとき", (done) => { sampleFetch("https://kiito.hatenablog.com/").then(response => { expect(response).toEqual("歩いたら休め"); done(); }); }); it("SHIFT_JISのページの時", (done) => { sampleFetch("https://monoist.atmarkit.co.jp/mn/articles/1806/12/news057.html").then(response => { expect(response).toEqual("日立は「カンパニー」から「ビジネスユニット」へ、成長のエンジンは「Lumada」 - MONOist(モノイスト)"); done(); }); }); });