LoginSignup
59
34

More than 3 years have passed since last update.

長野県版 新型コロナウイルス感染症対策サイト データ更新を自動化した話

Last updated at Posted at 2020-04-13

TL;DR

長野県版 非公式 新型コロナウイルス感染症対策サイトのデータ更新(Webスクレイピングしたり再エンコーディングしたりCSVからJSONへマッピングしたり)をGitHub Actionsを使って自動化しました。サイトのリポジトリにはデータファイルの管理をせずにアプリケーション関連のファイルのみを管理をするので開発もスッキリ。

開発したスクリプトはこちら:
- wataruoguchi/covid19_nagano_csv_to_json
- wataruoguchi/covid19_nagano_scraper

これらのスクリプトで作られたJSONファイルを使っているリポジトリはこちら:
- Stop-COVID19-Nagano/covid19

自己紹介

昔は高専生でした。悪いことしてなくてもディスられる世の中、怖い・・・
https://twitter.com/IiToshihide/status/1246487047545556992

目次

0. 経緯
1. オープンデータ自動ダウンロード & CSV -> JSON 変換
2. ニュース一覧をスクレイピング & JSON 変換
3. 自動更新されたファイルでサイトを自動ビルド
4. まとめ
5. 謝辞

0. 経緯

東京都とCode for Japanが開発した東京都 新型コロナウイルス感染症対策サイトと、それをforkして各地域のサイトが開発されているのを見て、出身地の長野県版に協力したいと思いcontributeを始めました。

一つ目のスクリプトを書いた後で、長野県版の先行作業されていた有志の方たちがデータを手作業で更新していることを知りました。その方達を助けられるよう、自動化に観点を置いてコードを書いてきました。この知識が他の自治体やプロジェクトの一助になれば、と思います。

1. オープンデータ自動ダウンロード & CSV -> JSON 変換

Contributeするにあたり最初に確認したのは、オープンデータの有無でした。幸いにも、長野県のサイトでCSVファイルを見つけることができました。しかし、これらの公開されていたファイルには以下のようにいくつかの問題がありました。

  1. 利用するのに難がある。ファイルタイトル(カラムヘッダではない)がついていたり合計行があったりする。
  2. ファイルエンコードがSHIFT JIS。UNICODEが欲しい。
  3. ファイル名が毎日変わる。ファイル名のsuffixに日付がつくので、毎日ファイル名が変わる。古い日付のファイルはサーバから削除される。ファイル名が変わることもある(hasseijoukyou0402.csv もあれば hasseizyokyo0411.csv もある)。

これらの問題を解決するためにWebスクレイピングしてCSVをJSONに変換するスクリプトを書きました。

  1. 長野県のページをスクレイピングし、公開されているCSVファイルのURLを取得する。
  2. ファイルをダウンロードし、エンコード変換したCSVファイルを保存する。
  3. CSVから不要な行を削除し、JSONにマッピングし、生成されたJSONファイルを保存する。

たまに出現する全角数字(!)を半角数字に変換したり、複数のファイルから data.json を作成する処理も同スクリプトでやっています。

これを自動で毎時間実行するための GitHub Actions ワークフローを作成しました。

毎時間実行するためには、scheduled event というEvent Triggerを使います。

...
on:
  schedule:
    - cron: "0 * * * *"
...

スクリプトを走らせて、新しいファイルが作成されたかを確認します。今回は git status | grep modified でチェックすれば十分でした。

新しいファイルが作成されていたらそれを git add & git commit して同リポジトリに保存します。

...
      - name: Commit files
        run: |
          git config --local user.email "wataru.oguchi.0to1@gmail.com"
          git config --local user.name "Wataru Bot"
          git status | grep modified && git add src/.encoded src/.json && git commit -v -m "[Bot] GitHub Actions - auto run" || true
...

これによって、同リポジトリに常に最新のCSVファイル及びJSONファイル(data.json)が自動で保存されるようになりました。(git pushもお忘れなく!)

2. ニュース一覧をスクレイピング & JSON 変換

グラフを表示するには data.json というファイルを参照している一方で、ニュース一覧には news.json というファイルを参照しています。県のサイトを見て手作業で更新されている様子でしたので、単純にWeb スクレイピングをし、一つ目のスクリプトと同様にJSONファイルに保存することとしました。Web スクレイピングをするスクリプトはこちら

こちらも前述したスクリプトと同様、GitHub Actions ワークフローを作成し、毎時間実行しています。

3. 自動更新されたファイルでサイトを自動ビルド

ここまでで必要なJSONの生成は自動化することができました。

実際のページは静的サイトなので、データを更新するためにはビルドする必要があります。ここでのタスクは以下の通りです。

  1. データが更新された時に再ビルドを行うため、データ生成スクリプト側で通知する。
  2. 実際にページをビルドするプロジェクトで通知を受け取る。
  3. 最新のデータをダウンロードして再ビルドを行う。

1. データ更新の通知を送信する

JSONデータを生成する wataruoguchi/covid19_nagano_csv_to_jsonwataruoguchi/covid19_nagano_scraper 側のGitHub Actionsを使います。上記で紹介したGitHub Actions ワークフローのスニペットにGitHub APIへPOSTリクエストを送る curl コマンドを加えます。

...
      - name: Commit files
        run: |
          git config --local user.email "wataru.oguchi.0to1@gmail.com"
          git config --local user.name "Wataru Bot"
          git status | grep modified && git add src/.encoded src/.json && git commit -v -m "[Bot] GitHub Actions - auto run" \
            && curl -X POST \
              -H "Authorization: Bearer ${{ secrets.ACCESS_TOKEN }}" \
              -H "Accept: application/vnd.github.everest-preview+json" \
              -H "Content-Type: application/json" \
              https://api.github.com/repos/Stop-COVID19-Nagano/covid19/dispatches --data '{"event_type": "build_application"}' \
            || true
...

変更点を抜粋したものが以下のスニペットです。


curl -X POST \
  -H "Authorization: Bearer ${{ secrets.ACCESS_TOKEN }}" \
  -H "Accept: application/vnd.github.everest-preview+json" \
  -H "Content-Type: application/json" \
  https://api.github.com/repos/Stop-COVID19-Nagano/covid19/dispatches \
  --data '{"event_type": "build_application"}'

GitHub API v3 の dispatch event を使い、Webサイトのリポジトリである Stop-COVID19-Nagano/covid19 に dispatch イベント { "event_type" : "build_application" } をPOSTしています。 secrets.ACCESS_TOKEN はrepo権限のみを持ったパーソナルアクセストークンを作成し、そのトークン値をwataruoguchi/covid19_nagano_csv_to_json リポジトリ側の Secrets に保存しています。前提として、イベントが送信される側のリポジトリの管理者権限を持っている必要があるかと思います。

2. データ更新の通知を受け取る

データ更新の通知を受信するためにはWebサイトのリポジトリ Stop-COVID19-Nagano/covid19 のGitHub Actions ワークフローを更新します。

イベントトリガーのところに、repository_dispatch とその types である build_application を追加します。

...
on:
  repository_dispatch:
    types: [build_application]
...

これだけの変更で dispatch event を受け取り次第、このworkflowが実行されるようになります。

注意すべき点は repository_dispatchmaster リポジトリに無いと動かないということ。ドキュメントにはデフォルトブランチ(私たちの場合はdevelopment)でも動くと書いてあったのに動作は確認できませんでした。( 軽く2時間は溶けました :/ )

3. 最新のデータをダウンロードしてビルド

最新のデータは全てスクリプトのリポジトリにあるので、ビルドをする前にshellスクリプトで全てのJSONファイルをダウンロードします。

実際のファイルはこちら (bin/cp_data.sh)

この bin/cp_data.sh を generate 時に実行するよう、package.json 内の scripts に変更を加えました。

...
"scripts": {
    "cp:data": "./bin/cp_data.sh",
    "generate:deploy": "yarn cp:data && yarn generate:deploy:orig",
    "generate:deploy:orig": "nuxt-ts generate",
}
...

generate:deploy:orig が元々 generate:deploy だったものです。新たにデータをダウンロードするスクリプト./bin/cp_data.shを実行するcp:dataを追加し、デフォルトで使われるgenerate:deployでこれを実行するよう変更しました。

4. まとめ

以上の変更で、手動で行ってきた以下のタスクが全て自動化されました。

  1. 県のサイトからCSVファイルを探してダウンロードする。
  2. CSVファイルをダウンロードしてJSONへ変換する。
  3. JSONが変わったときに、ページの再ビルドを行う。

同様に、自動化スクリプト側でデータ管理を行うことになり、Webサイトのリポジトリからデータ管理を外れたことで、以下の利益も生まれました。

  1. 同リポジトリの変更がデータの変更タイミングに依存せず、アプリケーション変更に集中できる。
  2. データに誤りがあったらデータ生成スクリプトの修正をすればいいだけなので、アプリケーション側でデプロイ等する必要がない。
  3. 以前同リポジトリで行っていたHTTP GETでの最新JSON取得を廃止し、ビルドのタイミングで行うためレンダリングパフォーマンスが良い。

5. 謝辞

長野県版を立ち上げてくださった方、長野県庁の中の人と連絡を取ってくださった方、長野県のオープンデータを整備されている方、アプリのメンテナンス/改善をしてくださった方、みなさんの力でこのページが生まれて、県内に住む方々から良いフィードバックを得られています。ありがとうございます。

東京都のメインプロジェクトから派生して、長野県だけでなく全国各地で同じようにプロジェクトが生まれています。これらのプロジェクトに時間と能力を費やしている方、Code for JapanのSlack チャンネル #covid19, #stopcovid19jp の方にも知識の提供をいただいています。ありがとうございます。

身近にいる人の感染がわかってからでは身を守るのが手遅れになるかもしれません。

感染を遅らせることができれば、医療機関も一人ひとりの患者の治療に時間をとれます。外出を控え、自分だけでなく、自分の大切な人たち、そしてその人たちの大切な人たちを守ることに協力してください。

59
34
1

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
59
34