PythonでTwitter BotをCloud Functionsで動かす

Python

市中にどのくらいコロナが蔓延しているか外出するたびに気になっていたのだが、いま住んでいる地域の情報をリアルタイムで伝えてくれるメディアがなかったので、自分で作った。すでに半年以上稼働しており安定してきたので、あとで思い出せるようにどうやってやったのかをまとめる。

やったこと

次のポストを行うTwitter Botの作成。

  • 毎日の新型コロナウイルス感染者数のポスト(自治体の公式発表にもとづく)
  • コロナ危険エリアを知らせてくれる色塗りマップの作成
  • コロナ感染者数のランキング
  • ワクチン接種数・接種率
  • 実効再生産数(Rt)のグラフ

サービス構成

  • Cloud Schedulerを使ってイベントをCloud Functionsに送る
  • Cloud Functionsは各自治(愛知県、名古屋市、豊田市、豊橋市、岡崎市、一宮市)および首相官邸のWebsiteをクロールし、その日の感染者数、前日の感染者数、人口、ワクチン接種数などを取得する。スクレイピングまたは、csvやxlsx、pdfなどのデータをダウンロードしてデータ化している。
  • スクレイピングまたはファイルから得たデータをGoogle Spreadsheetsに書き込んで保存する。過去のデータを使う場合は、このGoogle Spreadsheetsから読み込んで使う。
  • 加工したデータをTwitterにポストする。また、過去のポストしたデータをAPIで取得する。

技術的な詳細と開発の経緯

はじめはスクレイピングおよびデータ取得、Twitterへのポストをローカルでcronで動かすことにしていた。この時点でやっつけた課題は次のとおり。

  • PDFを含む複数の異なるWebサイトからのデータ取得。愛知県の対コロナ体制は非常に複雑であり、名古屋市・豊橋市・豊田市・岡崎市(途中から一宮市が追加)は独自にコロナ感染者や死亡者などを発表しており、愛知県はこれら以外の自治体分に関して発表している。
    • つまり、ひとつを見れば全部わかるサイトというのがなく、これら6つのすべてのWebサイトを見ないと、コロナ感染者数の全体像が見えないひどい仕様である。それぞれのウェブサイトは全く互換性がなく、PDFで発表したりベタ打ちhtmlだったりテーブルだったりするお役所行政。また、PDFは紙に印刷する用に作られており、データ提供のフォーマットとしては最悪。
    • PDFはCamelot-pyで、普通のhtmlはBeautifulSoupで、xmlはfeedparserで読み取っている。PDFがやはり一番曲者で、よくデータ位置がずれるし、そもそも数百ページのPDFを読み取るのにすごい時間とコンピューティングリソースがかかる。
    • htmlも曲者で、市の担当者がその日の気分で文章を変えたり文章の位置を変えたりするので、色んなパターンが来ても対応できるようにしないといけない。安定してデータを取ってこれるようになるまで時間が必要である(どんなパターンが来るのか学習する必要があるため)。
  • 色塗りマップの作成
    • 愛知県の地図上をコロナ患者の発生者数で色塗りをした。どこで感染が起こっているのかを視覚的にわかるようにするため。
    • これにはgeopandasを用いた。geopandasは地図上を色塗りできるライブラリで、インストールがやや面倒である。Linuxを使うかAnacondaを使えばインストールは簡単でよいが、Windowsでpipを使う場合はC++のコンパイラなどをいれる必要がある。
  • 実効再生産数(Rt)のグラフの作成
    • 実効再生産数を厳密に計算しようとすると、さまざまなパラメータが必要であり、素人には難易度が高い。参考はこちら
    • 簡易的な計算方法というのが提案されており、検証もされている。東洋経済の推定でもこの方法が使われている。今回はこの方法を使うことにした。
    • グラフ自体はmatplotlibを用いて描く。
  • ワクチン接種数と人口に対する割合
    • 政府CIOポータルのウェブサイトで掲載されているのだが、なぜか医療従事者向けはダッシュボードとは別に首相官邸サイトに記載されているため、全体数をリアルタイムに知るためには双方からデータを取得する必要がある。
    • 首相官邸サイトがたまにエクセルのファイル名を変えるのが曲者。

これらは、はじめはローカルのラップトップ(Ubuntu)で動かしていた。これがくせ者で、こどもがパソコンで遊んだあとに電源を消してしまったり、重い処理をして固まったままになってたりしてうまく動いていないことがあった。また、つけっぱなしなので電気代もそれなりにかかる。

  • この問題を解決するために、Cloud Functionsを使うことにした。
    • いま考えればHerokuとかのほうがよかったのかもしれない。
  • Cloud Functionsは完全に素人なので全然使い方がわからず、ちゃんと動くものがデプロイできるまでやや苦労した。
    • requirements.txtの書き方やコード自体のデプロイは比較的シンプル。
    • 料金体系が結構複雑。Cloud Schedulerの料金、デプロイ時のCloud Storage料金、Cloud Functionsの料金など全部でいくらかかるのかパッと見よくわからない。
    • /tmp/にファイルを保存できるというのがはじめ気づかなかった。
    • メモリ設定など。PDFを読み込む動作はかなりメモリを使うため、メモリをけちった設定になっているとメモリ不足で落ちる。どのくらいメモリが必要かの見積もりが重要。

コード

githubにある。が、もはや使っていないファイルも多く、参考になるかは不明。

コメント