フリーランスのためのネットビジネス専門学校 ネットで独立開業を目指す人を応援
フリーランスのためのネットビジネス専門学校 ネットで独立開業を目指す人を応援

node.jsでjQueryを使ってスクレイピングする

要約

  • Node.jsでスクレイピングする
  • jQueryを利用する
  • Promise,async/awaitで同期処理にする。なお同期処理に悪戦苦闘した。難しい・・・

動機

  • 自然言語の機械学習用データ集めのため、スクレイピングする必要があった。
  • Pythonでばかりコーディングするのも芸がない。DOMを操作するんだから、jQueryを使ってやろう。
  • Node.jsは前から興味があったけど、初めて触る。JSのお勉強がてらやってみるか。(※ワタクシのJavaScript知識は10年以上前で止まっていましたので。プロミス?なにそれ、消費者金融?って状態でした)

やりたいこと

  • とある、Webサイトの記事のURLを取得したい。
  • Webサイトには一覧ページがあり、1ページに50件程度の記事一覧がある。ページはパラメータで変えられる(https://hoge?page=2のような形で)
  • 記事一覧の各ページから、記事本文のURLと投稿日、記事タイトル等を取得する

やったこと

必要なライブラリのインストール

$ node -v # => v8.11.1
$ npm init
$ npm install jquery --save
$ npm install jsdom --asve

jqueryは趣旨のとおり。jsdomはjqueryをブラウザなしで利用するのに必要だった。

コーディング

ポイントは

  • https.getは非同期で動作するので、(同期させたいなら)Promiseオブジェクトを返す関数でラップしてやる(get_entry_titles)
  • GETで取得したHTMLをそのままjqueryへ突っ込むと windowがない といってエラーになるで、jsdomを利用する
  • 同期したいところをasync/await を使う。
const https = require("https"); //GETメソッドでリクエストするために
const util = require("util"); //format関数を利用するために
const jsdom = require("jsdom"); //jqueryをつかうために
const jquery = require("jquery"); //趣旨のとおり、DOM走査するために

// 記事一覧のページ
const URL = "https://hoge?page=%s";

// スクレイピングする処理(プロミスオブジェクトを返す) 
// 最近はfunctionで定義しないで、無名関数を変数に代入にするのがモダンなの?
function get_entry_titles(page){
    // プロミスをnewする
    return new Promise((resolve) => {
        // httpsリクエスト
        const req = https.get(util.format(URL,page), (res) =>{
            // このあたりは公式のドキュメント参考に
            var html = "";
            res.setEncoding('utf8');
            res.on('data',(chunk) => html += chunk);
            res.on('end',() => {

                // windowがないとjQueryが動かないそうで、以下の様にする模様
                const dom = new jsdom.JSDOM(html);
                const $ = (jquery)(dom.window);

                //スクレイプしたい処理をjQueryで記述
                $(".foo").each((index,element) =>{
                    // スクレイプ結果を出力
                    console.log(util.format(
                        "%st%st%s"),
                        page, //ページNo.
                        $(element).find(".bar").attr("href"), //リンクURL
                        $(element).find(".hoge").text()); //タイトル
                });
                //ここで処理完了なのでresolve。これにたどり着くのに悪戦苦闘した
                resolve();
            });
        });
        req.end();
    });
}

// メインのループ処理(ページ数文繰り返し) async関数にする
async function main(){
    // 1〜9ページ繰り返す
    for (var page=1; page < 10 ; page++){
        // awaitを付けて、1ページづづ同期する。じゃないとページ数だけが先にインクリメントされてしまう。
        await get_entry_titles(page);
    }
}

// 処理エントリ
main();

最後に

うむ、JavaScript、もう一度勉強しないと。10年の遅れをキャッチアップせねば。
なんとか動作はしたが、もっといいやり方とかがあるかもしれない。

[紹介元] jQueryタグが付けられた新着投稿 – Qiita node.jsでjQueryを使ってスクレイピングする

コメント

記事に戻る

コメントを残す