見出し画像

Node.jsでWEBデータを収集してCSV化する

WEB上のデータを手動でコピペするの大変・・と思い自動で保存してくれる処理を書きました。(参考にされる方はそのページの著作権について必ず確認してください)

確かWikipediaはスクレイピングが非推奨だったはず。API使って下さいねと公式が言ってます。が、今回は1ページだけのお試しということで🙃

この記事のゴール

これはフランスの画家ルノワールの作品一覧です。(Wikipediaより)これをCSVにしていきます。

スクリーンショット 2020-04-05 14.32.57

CSVにすると、スプレッドシートやExcelで保存・閲覧することもできます。ルノワールのデータをこんな感じにできました。

スクリーンショット 2020-04-05 14.37.28

ざっくり行った処理はこんな感じ。

①Node.jsでPuppeteerを動かす
②Puppeteerを使ってWikipediaにアクセス
③Wikipediaのデータを解析して配列にする
④配列からCSVを作成

Node.jsの環境を用意

ESNextの環境が必要なのでBabelを入れてください。

ここから必要なパッケージをインストールします。

yarn add -D puppeteer csv-stringify

puppeteerとは

Google製のNode.jsライブラリ。ブラウザ操作やスクリーンショットなども可能。スクレイピングやテストなどに使われます。

他にも、inputタグへの文字入力や、Basic認証が掛かっているページにアクセスすることも出来るらしいです。すごい・・。

csv-stringifyとは

Node.jsでCSVの生成ができるライブラリ

Puppeteerを使ってWikipediaにアクセス

puppeteerを使う上で必要な処理をmainに記述します。

const puppeteer = require('puppeteer');
const csv = require('./csv.js');

async function main() {
   console.log('run ...')
   const browser = await puppeteer.launch();
   const page = await browser.newPage();

   try {
       // レコードの取得
       const records = await fetchRecords(page);
       // CSV生成
       csv.create(records);
   } catch(error) {
       console.log('エラー:', error);
   } finally {
       await browser.close();
   }
}

「// レコードの取得」にあるfetchRecords()にWikipediaにアクセス&解析の処理を書いていきます。

async function fetchRecords(page) {
   console.log('fetch records ...')
   const BASE_URL = 'https://ja.wikipedia.org/wiki/ピエール=オーギュスト・ルノワール';
   await page.goto(BASE_URL);
   const records = await page.evaluate(() => {
       const listNode = document.querySelector('ul.gallery');
       const itemNode = listNode.querySelectorAll('li > div');
       const items = Array.from(itemNode);
       return items.map((item) => {
           const gallery = {};
           const text = item.querySelector('.gallerytext');
           const splitText = text.innerText.split(/『|』|。/);
           gallery['name'] = splitText[1];
           gallery['year'] = splitText[2];
           gallery['description'] = splitText[3];
           gallery['museum'] = splitText[4].replace(/\[\d+\]/g, '');
           const a = item.querySelector('.thumb > div > a');
           gallery['image'] = a.href;
           return gallery;
       })
   });
   return records;
}

page.goto(BASE_URL);でWikipediaのルノワールのページへアクセス。page.evaluateすることで要素を取得できるようになります。

その後は泥臭くdocument.querySelectorで欲しいデータを取得しています。(コードが汚い・・。)

最後にreturnしているrecordsの中身はこんな感じ。

スクリーンショット 2020-04-05 15.13.24

これをCSVにしていきます!

配列からCSVを作成

配列から見出し行を取り出し、stringifySyncのオプションに設定、生成したCSVをNode.jsのfs.writeFileSyncを使って出力しています。

const stringifySync = require("csv-stringify/lib/sync");
const fs = require("fs");
// 配列オブジェクトからcsvデータを作成
export const create = (records) => {
   console.log('CSV ...')
   const target = Object.getOwnPropertyNames(records[0])
   const columns = {};
   for (let key of target) {
       columns[key] = key
   }
   // 見出し行を指定
   const csvString = stringifySync(records, {
     header: true,
     columns,
     quoted_string: true
   });
   try {
       // csvファイルに出力
       fs.writeFileSync('src/output.csv', csvString);
       console.log('🎉 output complete!');
   }catch(error){
       console.log('エラー:', error);
   }
}

見出し行を指定しているcolumnsは、こんなオブジェクトが入っています。

{
   name: "name",
   year: "year",
   description: "description",
   museum: "museum",
   image: "image"
}

JavascriptのObject.getOwnPropertyNamesメソッドを使うとkeyを取得できます。その後に、fs.writeFileSync('src/output.csv', csvString);することでファイル出力しています。

$ npx babel-node src/index.js

実際に実行するとsrcディレクトリにoutput.csvファイルが生成されているはずです。

完成

スプレッドシートの「ファイル→インポート→ファイル選択」から生成したCSVファイルを指定します。

スクリーンショット 2020-04-05 15.24.11

これで完成🙌

スクリーンショット 2020-04-05 15.25.59

Node.jsを勉強したい場合はこちらの書籍が分かりやすかったです。


スキ頂けると嬉しいです〜