日頃救急車だったり消防車だったりが行きかっていると、その緊急車両がどこへ行くのだろうかと考えを巡らせてしまう方は少なくないはずです。消防への緊急通報番号である「119番」が創設された際には、本当に火災を発見して電話をして来た人と、半鐘の音を聞いて火災確認をしに来る人の区別が大変だったという逸話が残っているほど、そういった方々は世の中にいっぱいいるらしいです。
かくいう私もその1人で、どこかで火災が発生していると思ったら(安全を確保した上で)お散歩をしに行ってしまいそうな心をずっと持っています。とはいってもわざわざ毎回お散歩をするのも面倒な上、だいたいは迷惑なことも多いため、消防が出している出動情報を眺めるのに結局は落ち着いてしまいます。
というわけで全国の消防組織が出している出動情報を取得し、統一したフォーマットで出すツール「emergency-dispatch」を作ってみました。具体的にはWebサイト上に掲載されているものをスクレイピングで取得し、JSON及びRSSで取得できるようにするものです。かなり適当に作ったのですが、思ったよりもちゃんと動いて感動しています。
結論
- 基本的には各消防組織単位のJSON
- RSS 2.0フィードもついでに生成
- まだまだ対応している場所が少ない
emergency-dispatch
「emergency」は緊急、「dispatch」は出動という意味を持つ英単語であることが知られています。統一したフォーマットで作りたいなあと感じた月曜日の深夜4時の頭ではこの2つを適当にくっつけて「emergency-dispatch」とするのが精一杯でしたが、まあその名前の通り緊急車両の出動を知ることが出来るツールなのでまあ良いでしょう。
実装は何となく触ってみたかったRustのreqwest
とscraper
を使って実装しました。市役所のサイトがそれぞれの地方で微妙に違うのと同様に、消防の出動情報Webサイトは千差万別で、共通項がそんなにない場合が多いため、消防組織ごとに異なるパーサーを実装しています。非同期処理とかいう贅沢なことはせず、cargo run
をするといい感じにdist/
へドカドカとファイルが積まれるという古き良きシステムとなっています。
このパーサーを手で実装するのは意外と骨が折れる、というよりもパターンを読み取ってそれを実装するのがかなり面倒ということで、ある程度人間の手の温かみによる解析を行い、それをGitHub Copilot君に実装してもらうといった形を取りました。何も無いところに突っ込ませるとえらい目に合うのが†AIを活用したプログラミング†でありがちな話ではありますが、自然言語を人間が作った言語に「翻訳する」といった使い方はそんなに失敗しない印象があったのでやってみました。
例えば札幌市のパーサー(結果は011002.json
へ出力されます)の実装を行う際には、「現状「disaster_text」の出力は「"現在の災害出動 \n\u{3000}\u{3000}●救助出動 \n\u{3000}\u{3000}\u{3000}・北区北22条西2丁目(07時11分) \n\u{3000}\u{3000}●ガス漏れ出動 \n\u{3000}\u{3000}\u{3000}・清田区北野4条5丁目(06時34分) \n \n\u{3000}"」となっています。ここからテキストを抽出し、「救助出動 北区北22条西2丁目(07時11分)ガス漏れ出動 清田区北野4条5丁目(06時34分)」のような出力になるように修正してください」と指示を出し、まあよしなに実行してみて修正し、何も無い時の例外処理を手で書いたりしつつをするとよしなに出来てしまう、といった感じでした。
JSONとRSS
各消防組織向けのパーサーから得られた情報はまとめてそのパーサー内でJSONにしてしまいます。この出力フォーマットは最低限共通であろうものにまとめることにしました。
{
"disasters": [
{
"address": "例示県例示市なんちゃら1丁目", # 都道府県から始まる住所
"time": "01:23", # 出動時刻(ソースとなる機関によって異なる場合がある)
"type": "火災" # 出動種別
},
{
"address": "例示県例示市大字ほにゃらら234",
"time": "00:12",
"type": "航空隊支援"
} # このように複数の出動情報が存在する場合がある。何も無い場合は空配列が返される。
],
"jisx0402": "999999", # 6桁の地方公共団体コード
"source": [
{
"name": "例示市消防本部", # ソースとなる機関名
"url": "https://example.com/index.html" # ソースページ
}
]
}
まあ見ればわかるようなシンプルなJSONです。これによって、特にその地域に住んでいる人にとっては特定のJSONを取得し続けるだけ(?)の、適当なフロントエンドをこさえやすい形でもある分かりやすいデータを得ることが出来ます。
しかしながら、これに満足せず、全国の出動情報を知りたいという欲望がギラギラな私のような人もいるでしょうから、そうした人向けにJSONデータから全ての情報をまとめたRSSファイルを生成するようにしています。
JSONのtime
の仕様を決めた際には気づかなかったのですが、実は世の中には日付というものがあるらしく、特に深夜に取得した場合においてはその日付が重要だったりします。RSS 2.0の仕様において、日付は基本的にISO8061形式で書くことになっておりますので、フィードを生成する時の時間と比較して、その出動情報のtime
が10分以上未来の場合は前日のものとして取り扱う、といったような雑な対策を施したりしました。そのうち直します。
このRSSファイルでは現状対応している北海道札幌市・青森県つがる市・千葉県市川市・新潟県長岡市・京都府京都市・奈良県生駒市の現状出ている災害情報を知ることが出来ます。一部自治体(生駒市とか)においては過去の出動分を知ることは容易なのですが、情報の粒度を合わせるために入れ込みませんでした。これは各消防組織におけるJSONでも一緒です。
最後に
さて、雑な紹介でしたが「 emergency-dispatch 」を適当にRustで実装してみたという記事でした。Pythonに比べればネット上の知見も少なく、惑うところが無かったわけではないのですが、かなり使いやすかったという印象を持ちました。この「emergency-dispatch」のソースコードを公開しているので、適当に興味がある方は見て下さると良いかと思います。
薄々お分かりかと思うのですが、mk-mode.comさんのところでフィード・JSON・当日の情報提供の提供が終了してしまったことが開発の強い動機です。元々mk-modeさんの消防出動情報が更新されているのを見て、何となく日本は忙しいんだなあと思っていた小さな頃があったこともあり、適当に実装してしまいました。
著作権についてですが、一般に消防の出動情報は単なる事実の伝達であり、「思想又は感情を創作的に表現したもの」に入るとは到底思えませんが、明示的に転載等を禁止している自治体のものは実装しないつもりです。また一応Webからアクセス可能な形で置いてはありますが、一応個人用なので、過度なアクセスは控えてくれると嬉しいです。Rustの環境を整えるのはC++とかに比べればよっぽど楽であることから、個々人がよしなにビルドしてくれると思っておくことにしておきます。