LoginSignup
1
0

More than 3 years have passed since last update.

「福井県オープンデータ ごみ収集日一覧CSVをJSONに変換するツール」README

Posted at

※この記事は、私がGitHubに公開しているnode.js製ツール「福井県オープンデータ ごみ収集日一覧CSVをJSONに変換するツール」のREADMEを転載したものです。
解説は「恋に落ちるコード.js」の絵子と樹里です。


福井県オープンデータ ごみ収集日一覧CSVをJSONに変換するツール

福井県オープンデータライブラリ」で公開されている、県内17市町の「ごみ収集日一覧」データの形式を、CSV(Shift-JIS)からJSONに変換します。

Description

樹里「というわけで、福井県内自治体のごみ収集日一覧JSONデータを作成するアプリを作ってみた」
絵子「ほう。なんでまた突然」
樹里「それがな、久しぶりに福井県オープンデータに公開されてるデータを使って、アプリでも作ってみようとしたんだがな」
絵子「福井県は昔からオープンデータの公開に熱心だよね」
樹里「で、ごみ収集日一覧のデータを見てみたんだが、なんとShift-JISのCSVなんだよ。この令和の時代に」
絵子「うーん。確かにそのままだと扱いにくいよね」
樹里「Shift-JISのCSVなんだよ。この令和の時代に
絵子「2回言わなくていいよ。あと太字にしなくてもいいよ」
樹里「これではどうしようもないので、まずはちゃんとしたUTF-8のJSONに変換するツールから作ってみたわけだ」
絵子「なるほど。経緯はよくわかった」

Usage

樹里「使い方は簡単。Node.js製のアプリなので……」

git clone https://github.com/8amjp/fukui-opendata-gomisyusyubi-json.git
cd fukui-opendata-gomisyusyubi-json
npm install

樹里「上記のコマンドでインストールして、」

node index.js

樹里「と実行すれば、distディレクトリにJSONデータが出力される」
絵子「あら本当に簡単」
樹里「じゃあ、アプリがどういう動きをするのか解説しよう」

index.js

樹里「まずは、メインとなるコードだ」

index.js
/*
  「福井県オープンデータライブラリ」の「ごみ収集日一覧」ページで公開されている
  収集日のCSVデータ(Shift-JIS)をJSONに変換します。
*/

const scraper = require('./lib/scraper');
const generator = require('./lib/generator');
const page = 'https://www.pref.fukui.lg.jp/doc/toukei-jouhou/opendata/list_ct_gomisyusyubi.html'; // 「ごみ収集日一覧」ページのURL

(async () => {
    // ページ内の17市町のCSVデータのURLを取得
    const resources = await scraper.scrape(page)
    // すべてのCSVを取得してJSONに変換して出力
    await Promise.all(resources.map(resource => generator.generate(resource)))
    console.log('できたよ!')
})();

絵子「scrapergeneratorっていうのが、樹里が作ったモジュール?」
樹里「そう。scraperで「ごみ収集日一覧」ページからCSVへのリンクを取得している。で、generatorでCSVを取得してJSONに変換している」
絵子「なるほど」
樹里「では、各モジュールの動きをみてみよう」

lib/scraper.js

樹里「次に、ページをスクレイピングして、CSVへのリンクを取得するscraperモジュールだ」

lib/scraper.js
/*
  指定されたページ内の、CSVへのリンクをを取得します。
*/
const fetch = require('node-fetch');
const cheerio = require('cheerio');
const url = require('url');

module.exports.scrape = async (page) => {
    // 指定されたページのHTMLを取得する
    const response = await fetch(page)
    const body = await response.text()
    // cheerioでページをスクレイピング
    const $ = await cheerio.load(body)
    // 末尾が'.csv'のリンクをすべて取得
    const relativePaths = await $('a[href$=".csv"]').map((i, el) => $(el).attr('href')).get()
    // 絶対パスに変換
    const absolutePaths = await relativePaths.map(path => url.resolve(page, path))
    return absolutePaths
}

樹里「スクレイピングにはcheerioというライブラリを使用している」
絵子「知ってる。jQueryっぽく操作できるやつだよね」
樹里「そう。そのcheerioで、属性セレクターを使って、href属性 が ".csv" で終わるa要素、すなわちCSVへのリンクを取得してだな、その配列を返している」
絵子「なるほど」

lib/generator.js

樹里「最後に、データの変換を行うgeneratorモジュールだ」

lib/generator.js
/*
  指定されたURLのCSVを取得し、文字コードをShift-JISからUTF-8にに変換して出力します。
*/
const path = require('path');
const fs = require('fs-extra');
const fetch = require('node-fetch');
const parse = require('csv-parse/lib/sync');

module.exports.generate = async (resource) => {
    // ファイル名を生成
    const file = path.basename(resource, '.csv') + '.json'
    // 指定されたURLのCSVを取得
    const response = await fetch(resource)
    const buffer = await response.arrayBuffer()
    // CSVの文字コードをShift-JISからUTF-8にに変換
    const decoder = new TextDecoder("Shift_JIS")
    const csv = decoder.decode(buffer)
    // CSVをJSONに変換
    const json = await parse(csv, { columns: true, trim: true })
    // JSONを出力
    const result = await fs.outputJson(path.join('dist', file), json, { spaces: 4 })
    return result
};

樹里「まず、node-fetchでCSVを取得して、Shift-JISからUTF-8に変換する」
絵子「へー、TextDecoderっていうので文字コードを変換できるんだね」
樹里「で、csvというライブラリのcsv-parseという機能を使って、CSVをJSONに変換しているわけだ」
絵子「便利なライブラリだねー」

樹里「さて、処理の結果、このようなJSONが出力される」

[
    {
        "行": "あ",
        "音": "あ",
        "町名": "在田町",
        "読み": "あいだ",
        "燃える": "火・金",
        "燃えない": "2・4木",
        "プラスチック製容器包装": "月",
        "カン": "1・3水",
        "ビン": "4水",
        "ペットボトル": "2水",
        "ダンボール": "3水",
        "蛍光灯": "4木",
        "キーワード": "清水",
        "備考": "清水南"
    },
    // 以下略

絵子「これ、キーが日本語になってるけど問題ないの?」
樹里「ああ、仕様に則った正しいJSONだぞ」
絵子「へー、そうなんだ」
樹里「なにより、Shift-JISのCSVよりははるかに扱いやすい」
絵子「よっぽどキライなんだね」


樹里「……さて、無事にShift-JISのCSVをJSONに変換できた」
絵子「めでたしめでたし、だね」
樹里「いやいや、データの形式を変換しただけで、何も出来上がってないぞ。大事なのは、このデータを使ってどんなアプリを作るかだ」
絵子「そりゃそうだ。さ、次はアプリ制作に挑戦だ!」

Author

8amjp

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0