Node.jsでWEBデータを収集してCSV化する
WEB上のデータを手動でコピペするの大変・・と思い自動で保存してくれる処理を書きました。(参考にされる方はそのページの著作権について必ず確認してください)
確かWikipediaはスクレイピングが非推奨だったはず。API使って下さいねと公式が言ってます。が、今回は1ページだけのお試しということで🙃
この記事のゴール
これはフランスの画家ルノワールの作品一覧です。(Wikipediaより)これをCSVにしていきます。
CSVにすると、スプレッドシートやExcelで保存・閲覧することもできます。ルノワールのデータをこんな感じにできました。
ざっくり行った処理はこんな感じ。
①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の中身はこんな感じ。
これを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ファイルを指定します。
これで完成🙌
Node.jsを勉強したい場合はこちらの書籍が分かりやすかったです。
スキ頂けると嬉しいです〜