トップ画像イメージ

オープンデータをどういう風に活用したらいいのか?

折角オープンデータの記事も書いてみたことだし、自治体のオープンデータを使ってLINE BOTを作成してみました!

前回の記事で折角自治体のオープンデータを取得してみましたので、今回はオープンデータをリアルタイムに取得し、ユーザーに教えることをしてみようと思い、またまたLINEBotを作成してみました⭐️

今回もさっと作成してみたかったので、一番慣れているRailsと、Herokuを使って、WebAPIを作成してみました。

実際は、Railsで無くても十分な気がしますが、ご了承ください。

実際に出来上がったもの

こちらです。

Line Botイメージ

福岡県オープンデータの「福岡県 感染症発生動向調査週報」を利用させていただきました。

こちらでは、データをCSVとして公開するだけでなく、APIを使って、JSON形式でリアルタイムにデータを取得することが出来るようになっているので、次のような機能を盛り込んでみました。

  • リアルタイムにオープンデータを取得
    • 最新のオープンデータを取得し、インフルエンザの流行状況をお知らせ
    • 最新と最新から1個前のデータを取得し、インフルエンザの流行状況の増減をお知らせ

※正確に言えば、「福岡県に報告があった、該当する1週間で、1医療機関に何名辺りのインフルエンザの患者さんが確認されたか」というデータのようです。

イメージ

botイメージ1

ユーザーが「先週比」と送ると、 最新のデータと、最新から1個前のデータを取得し、人数の差分を返却します。

botイメージ2

ユーザーが「最新」と送ると、 最新のデータから、人数を返却します。

参考にさせていただいたサイト

Line-botをrailsで作ってみた。

【Rails】1時間ぐらいで簡単にLINEのBot開発をしよう-アンケート集計Bot基礎-【画像付き】

こちらで、LINEのユーザーからメッセージを飛ばされた時の取得方法、メッセージを返却する方法を参考にさせていただきました。

コード部分

コントローラー

class LinebotController < ApplicationController
  require 'line/bot'
  require 'net/http'
  protect_from_forgery :except => [:shuhou]

  def client
    @client ||= Line::Bot::Client.new { |config|
      config.channel_secret = ENV["LINE_CHANNEL_SECRET"]
      config.channel_token = ENV["LINE_CHANNEL_TOKEN"]
    }
  end
  #上のLINE_CHANNEL_SECRETなどの設定は参考サイトをみてください。環境変数を設定する必要があります。
  #api部分のメソッド(ユーザーからのメッセージの内容により返却する値を変更)
  def shuhou
    body = request.body.read
    events = client.parse_events_from(body)
    signature = request.env['HTTP_X_LINE_SIGNATURE']
    unless client.validate_signature(body, signature)
      head :bad_request
    end
    events.each do |event|
      message = event.message['text']
      #ユーザーから「最新」と送られた場合
      if message.include?("最新")
        resources = get_recent_id()
        recent_updated_id = resources[resources.length - 1]["id"]
        records = get_shuhou(recent_updated_id)
        res_str = ["1医療機関でインフルエンザの感染が確認された人数は\n\n"]
        #recordsをeachで回し発生地点毎のインフルエンザ倍率を配列に格納
        records.each do |record|
          if record["自治体名"] == record["地点名"]
            timei = record["自治体名"]
          else
            timei = record["自治体名"] + record["地点名"]
          end
          res_str << "#{timei}:#{record["(インフルエンザ)"]}人\n"
        end
        res_str << "\n\nです。\n(例)\n◯◯市:1人(〇〇市の1医療機関で、1週間辺りに1人のインフルエンザの患者が確認された。)"
        return_str = res_str.join("")
      #ユーザーから「先週比」と送られた場合
      elsif message.include?("先週比")
        resources = get_recent_id()
        recent_updated_id = resources[resources.length - 1]["id"]
        second_updated_id = resources[resources.length - 2]["id"]
        recent_records = get_shuhou(recent_updated_id)
        next_records = get_shuhou(second_updated_id)
        res_str = ["1医療機関でインフルエンザの感染が確認された人数の先週比は\n\n"]
        #最新の週報と1個前の週報で人数を比較
        recent_records.each do |recent|
          next_records.each do |second|
            if (recent["自治体名"] + recent["地点名"] ) == (second["自治体名"] + second["地点名"] ) 
              num = (recent["(インフルエンザ)"].to_f - second["(インフルエンザ)"].to_f).round(1)
              num = "+" + num.to_s if num >= 0
              if recent["自治体名"] == recent["地点名"]
                timei = recent["自治体名"]
              else
                timei = recent["自治体名"] + recent["地点名"]
              end
              res_str.push("#{timei}:#{num}人\n")
            end
          end
        end
        res_str << "\n\nです。\n(例)\n◯◯市:+1人(〇〇市の1医療機関で、先週と比較して1週間辺り、インフルエンザの患者数が1人増えた。)"
        return_str = res_str.join("")
      #それ以外は使い方を送信する。
      else
        return_str = return_str3 = "使い方\n\n福岡県が公開している「福岡県 感染症発生動向調査週報」のデータを元に、\n「1週間における、1医療機関当たりのインフルエンザの感染が確認された人数」\nをお知らせします。\n「最新」と送信すれば、最新の人数を、「先週比」と送信すれば、前回の報告と比較した人数の増減をお知らせします。"
      end
      case event
      when Line::Bot::Event::Message
        case event.type
        when Line::Bot::Event::MessageType::Text
          message = {
            type: 'text',
            text: return_str
          }
          client.reply_message(event['replyToken'], message)
      end
    end
    head :ok
  end

  #感染症週報のオープンデータの公開状況を取得する。resources["result"]["resources"][添字]["id"]で添字番目のオープンデータリソースidを取得
  def get_recent_id
    uri = URI.parse("https://ckan.open-governmentdata.org/api/3/action/package_show?id=43dd36e0-fc93-40af-8215-c17cbf964cae")
    response = Net::HTTP.get_response(uri)
    json = JSON.parse(response.body)
    resources = json["result"]["resources"]
    return resources
  end
  #指定したリソースidの感染症週報のデータを取得する。
  def get_shuhou(resource_id)
    uri = URI.parse("http://data.bodik.jp/api/action/datastore_search?resource_id=" + resource_id)
    response = Net::HTTP.get_response(uri)
    json = JSON.parse(response.body)
    records = json["result"]["records"]
    return records
  end
end


router

Rails.application.routes.draw do
  # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
  
  post '/shuhou' => 'linebot#shuhou'
end

これだけです。

やってることは超単純で


ユーザーからのメッセージを取得⇨メッセージの内容で、取ってくるオープンデータを変える⇨ 取ってきたオープンデータをちょっとだけ加工して、ユーザーに返す


としているだけです。

まとめ

  • 自治体にもよるけど、オープンデータもWebAPIにより、データをリアルタイムで取得することが出来るようになっている
  • データの取得は単なるHTTPのリクエストなので、Webの知識があって、少し触ればすぐにわかる
  • LINEとのメッセージのやり方も先人の知恵があるので、簡単に出来る
    • 実際このアプリは1日でできました
  • ただし、Herokuの無料モードでやっているので、速度は・・・

というところです。

2019-11-10追記 視覚的に分かりやすいように、グラフ機能を追加しました。記事はこちら

最後に、一応このLINEBotの友達追加用のQRコードを貼っておきます。

QRコード