Node.js、request、cheerioを使用して簡単なWebスクレイピングを設定する方法

提供:Dev Guides
移動先:案内検索

序章:

このチュートリアルでは、 Hacker News のフロントページをスクレイプして、すべての上位のリンクと、そのメタデータ(タイトル、URL、受け取ったポイント/コメントの数など)を取得します。 これは、node.jsを使用してWebページからデータを抽出する多くの手法の1つであり、主にサーバー用に特別に設計されたjQueryのサブセットを実装するMatthewMuellerによるcheerioというモジュールを使用します。

Cheerioは、jQueryの操作に既に慣れている場合は、軽量、高速、柔軟性があり、使いやすいです。 また、MikaelRogers'の優れたrequestモジュールを簡略化されたHTTPクライアントとして利用します。

要件:

node.js、jQuery、およびSSHを使用したVPSへの接続などの基本的なLinux管理タスクに既に精通していることを前提としています。

node.jsに慣れていない場合、またはまだインストールしていない場合は、上記の「記事とチュートリアル」セクションを参照して、オペレーティングシステムのインストール手順を確認してください。

コード:

NPMを使用して必要なモジュールをインストールするには、次のコマンドを入力するだけです。

npm install request cheerio

これにより、現在の作業ディレクトリにのみモジュールがインストールされます。

モジュールをグローバルにインストールするには:npm install -g request cheerio

scrape.jsというファイルを作成し、次の行を追加します。

var request = require('request');
var cheerio = require('cheerio');

これにより、すべてのモジュール依存関係が読み込まれます。

ここで、Hacker Newsのフロントページに簡単なリクエストをロードし、エラーが発生せず、HTTPステータスコードが200の場合は、ページのHTMLコードを表示します。

次の行をファイルに追加します。

request('https://news.ycombinator.com', function (error, response, html) {
  if (!error && response.statusCode == 200) {
    console.log(html);
  }
});

node scrape.jsを使用してスクリプトを実行してみると、ターミナルウィンドウにHTMLコードが記録されているはずです。

目的のメタデータを抽出する方法を知るには、HTMLコード内で要素がどのように構造化されているかを知る必要があります。 推奨される方法は、Google Chromeに組み込まれているWeb開発ツールを使用して、Webページを右クリックし、[要素の検査]を選択するだけで、Webページ上の目的のターゲット要素を検査することです。

この例では、ChromeでHacker Newsを開き、右クリックしてトップランキングストーリーのタイトルを調べました。

Web開発者コンソールをざっと見てみると、「comhead」という名前のクラスが追加された各「span」要素を選択し、jQueryを使用してその上の「a」要素を選択するだけでよいという結論に達しました。 API関数prev()を使用すると、上位30のリンクすべてとそのタイトルを簡単に解析できます。

リクエストコードを次のように変更することで、私の仮定をテストできます。

request('https://news.ycombinator.com', function (error, response, html) {
  if (!error && response.statusCode == 200) {
    var $ = cheerio.load(html);
    $('span.comhead').each(function(i, element){
      var a = $(this).prev();
      console.log(a.text());
    });
  }
});

予想どおり、コードを実行すると、30タイトルのリストが表示されます。 残りのメタデータを解析するために、もう少し変更してみましょう。

request('https://news.ycombinator.com', function (error, response, html) {
  if (!error && response.statusCode == 200) {
    var $ = cheerio.load(html);
    $('span.comhead').each(function(i, element){
      var a = $(this).prev();
      var rank = a.parent().parent().text();
      var title = a.text();
      var url = a.attr('href');
      var subtext = a.parent().parent().next().children('.subtext').children();
      var points = $(subtext).eq(0).text();
      var username = $(subtext).eq(1).text();
      var comments = $(subtext).eq(2).text();
      // Our parsed meta data object
      var metadata = {
        rank: parseInt(rank),
        title: title,
        url: url,
        points: parseInt(points),
        username: username,
        comments: parseInt(comments)
      };
      console.log(metadata);
    });
  }
});

追加されたコードの機能の概要は次のとおりです。

前の要素を選択します。

var a = $(this).prev();

「a」要素の2レベル上の要素を解析して、ランクを取得します。

var rank = a.parent().parent().text();

リンクタイトルを解析します。

var title = a.text();

「a」要素からhref属性を解析します。

var url = a.attr('href');

HTMLテーブルの次の行からサブテキストの子を取得します。

var subtext = a.parent().parent().next().children('.subtext').children();

子供から関連データを抽出します。

var points = $(subtext).eq(0).text();
var username = $(subtext).eq(1).text();
var comments = $(subtext).eq(2).text();

変更されたスクリプトを実行すると、次のようなオブジェクトの配列が出力されます。

[ { rank: 1,
    title: 'The Meteoric Rise of DigitalOcean ',
    url: 'http://news.netcraft.com/archives/2013/06/13/the-meteoric-rise-of-digitalocean.html',
    points: 240,
    username: 'beigeotter',
    comments: 163 },
  { rank: 2,
    title: 'Introducing Private Networking',
    url: 'https://www.digitalocean.com/blog_posts/introducing-private-networking',
    points: 172,
    username: 'Goranek',
    comments: 75 },
...

それは'それです!抽出されたデータをMongoDBやRedisなどのデータベースに保存して、さらに処理できるようになりました。 以下は、scrap.jsファイルの完全なソースコードです。

var request = require('request');
var cheerio = require('cheerio');

request('https://news.ycombinator.com', function (error, response, html) {
  if (!error && response.statusCode == 200) {
    var $ = cheerio.load(html);
    var parsedResults = [];
    $('span.comhead').each(function(i, element){
      // Select the previous element
      var a = $(this).prev();
      // Get the rank by parsing the element two levels above the "a" element
      var rank = a.parent().parent().text();
      // Parse the link title
      var title = a.text();
      // Parse the href attribute from the "a" element
      var url = a.attr('href');
      // Get the subtext children from the next row in the HTML table.
      var subtext = a.parent().parent().next().children('.subtext').children();
      // Extract the relevant data from the children
      var points = $(subtext).eq(0).text();
      var username = $(subtext).eq(1).text();
      var comments = $(subtext).eq(2).text();
      // Our parsed meta data object
      var metadata = {
        rank: parseInt(rank),
        title: title,
        url: url,
        points: parseInt(points),
        username: username,
        comments: parseInt(comments)
      };
      // Push meta-data into parsedResults array
      parsedResults.push(metadata);
    });
    // Log our finished parse results in the terminal
    console.log(parsedResults);
  }
});