Express+axios+cheerioで簡易Webスクレイピング

# はじめに

Webスクレイピングってなんぞ？というレベルだったので、色々調べていた時に目についた「自作スクレイピングアプリ」というものをやってみた時の備忘録です。

私と同じような「Webスクレイピング？なにそれ美味しいの？」って人向けの記事になります。

# 概要

- Webスクレイピングとは？
- 簡単に実装

# Webスクレイピングとは

Webスクレイピングとは、Webサイトにある情報を解析し、特定の情報を取得することで、取得した大量の情報は集計、分析など様々なことに利用されます。

サイトによってはスクレイピングを禁止している場合もあり、そうでないサイトから取得したデータについても取り扱いには十分注意しましょう。

# 簡単に実装

今回の実装で使用するツールは以下となります。

- macOS Sonoma 14.0
- VSCode
- Node.js v18.17.0
- express（Node.jsのフレームワーク）
- axios（HTTPクライアント）
- cheerio（スクレイピング用のライブラリ）

端末にNode.jsがインストールされている前提で進めますので、インストールされていない方は下記からインストールをお願いします。

https://nodejs.org/en

まずは作業用のワークスペースを作成します。

```sh
mkdir web_scraping_workspace
```

![スクリーンショット 2023-10-24 20.19.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1021235/017e4281-a1d9-1c03-60bf-dc2f7337a23f.png)

続いてVSCodeで作成したディレクトリを開いてください。

```sh
code web_scraping_workspace
```

![スクリーンショット 2023-10-24 20.20.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1021235/15fbc5d3-378f-a53b-229e-d262f30e53cb.png)

開いたディレクトリ内で`npm init`を実行します。色々と入力を求められますが、全てEnterでOKです。

```sh
npm init
```

![スクリーンショット 2023-10-24 20.21.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1021235/055b19e4-cdc2-c3b6-4a91-fe63f336d50a.png)

ここから必要なモジュールをインストールしていきます。

- express
```sh
npm i express
```

- axios
```sh
npm i axios
```

- cheerio
```sh
npm i cheerio
```

全てインストールできました。

![スクリーンショット 2023-10-24 20.23.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1021235/88e1efe3-b6a7-aaf8-44a7-10cc321cfbfc.png)

expressのサーバを起動するためのファイル`index.js`を作成します。

![スクリーンショット 2023-10-24 20.24.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1021235/78933ebd-b49f-763e-ba90-5f7e2f533d3e.png)

```index.js
// expressのインポート
const express = require("express");

// expressのアプリケーションを定義
const app = express();

// expressのアプリケーションを、ポート8000番でリッスン状態にする
app.listen(8000, console.log("server is running."));
```

サーバーをコマンドから起動するために、package.jsonのscriptsを変更しましょう。

![スクリーンショット 2023-10-24 20.27.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1021235/9ad7c7e6-a47a-9f96-f504-69d26a8e69cc.png)

`"dev": "node index.js"` に修正します。
これにより、`npm run dev`コマンドを実行時、index.jsのファイルがサーバーとして読み込まれます。

![スクリーンショット 2023-10-24 20.27.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1021235/d2f1e7e0-580d-f275-8cf0-04c43375fc1e.png)

コマンド `npm run dev` で起動すると、

![スクリーンショット 2023-10-24 20.28.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1021235/8f25c334-f20b-0fb0-13e1-e0dcc124ce12.png)

index.jsで書いたログがコンソールに出力されました。これでサーバーの準備は完了です。

![スクリーンショット 2023-10-24 20.28.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1021235/894ea83f-87f2-5fed-73e8-8f4daf0990e3.png)

ここからは実際にスクレイピングのための処理を記述していきます。

HTTP通信をするためのaxiosに、スクレイピング対象となるWebサイトのURLを渡してあげます。

```index.js
// expressのインポート
const express = require("express");

// 追加
const axios = require("axios");
const cheerio = require("cheerio");

// expressのアプリケーションを定義
const app = express();

// 追加
// スクレイピング対象となるWebサイトのURLを設定
const URL = "https://search.rakuten.co.jp/search/mall/headphones/";

// 追加
axios(URL).then((response) => {
  // スクレイピング対象のページの解析結果を取得
  const htmlParser = response.data;
  console.log(htmlParser);
});

// expressのアプリケーションを、ポート8000番でリッスン状態にする
app.listen(8000, console.log("server is running."));
```
この状態で再び起動すると、なにやら大量の文字が表示されました。
これはWebサイトのHTMLになります。

![スクリーンショット 2023-10-24 20.35.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1021235/3009a618-a456-c43a-b753-1b484f8860f4.png)

ブラウザのDeveloperToolsで右側に表示されているこちらです。

![スクリーンショット 2023-10-24 20.37.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1021235/1227542f-7a3a-6530-1aec-44a0a0ce4faa.png)

これだけでは情報が多すぎるため、欲しい情報だけに絞ります。
今回は金額だけにしてみましょう。（商品名のクラス名を指定してみても上手く取得できなかったため...）

cheerioのload()の引数に、htmlParserを渡してあげることでスクレイピングの準備ができます。

ここから、each()を使用してHTML要素にアクセスしていきます。

find()の引数にクラスセレクタを渡してあげると、

```index.js
// expressのインポート
const express = require("express");

const axios = require("axios");
const cheerio = require("cheerio");

// expressのアプリケーションを定義
const app = express();

// スクレイピング対象となるWebサイトのURLを設定
const URL = "https://search.rakuten.co.jp/search/mall/headphones/";

axios(URL).then((response) => {
  // スクレイピング対象のページの解析結果を取得
  const htmlParser = response.data;

  // 追加
  // 解析結果の読み込み
  const $ = cheerio.load(htmlParser);

  // HTMLのクラス名を指定し、要素を全て取得
  $(".searchresultitem", htmlParser).each(function () {
    const price = $(this).find(".price--OX_YW").text();
    console.log(price);
  });
});

// expressのアプリケーションを、ポート8000番でリッスン状態にする
app.listen(8000, console.log("server is running."));
```

金額情報が取得できました。

![スクリーンショット 2023-10-24 21.15.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1021235/68a3e17c-194b-58a1-f88e-6334c0b2b337.png)

スクレイピング処理の実装はここまでになります。

余談ですが、ソースを書き換えるたびにサーバーの再起動をするのが面倒ですよね。
そこで、`nodemon`というnpmライブラリを使用することで、ソース保存時に自動的に再起動させることができます。

```sh
npm i nodemon
```

package.jsonのscriptも書き換えましょう。

![スクリーンショット 2023-10-24 21.53.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1021235/cafc0a5e-7ca9-ad63-a045-e5aaf1129ef1.png)

これで修正＋保存で自動的にサーバーが再起動されるようになりました。

# 最後に

最低限の内容しか触れていませんが、スクレイピングってどうやるの？という方の参考になれば幸いです。

最後まで読んでいただきありがとうございました。

- 参考動画

https://youtu.be/NiLZX4Jorws?si=asU9Pk1sfSfrFdeR