Ruby
Weather
花粉

Ruby + Mechanize で Yahoo! JAPAN の花粉飛散予報を取得する(2018年版)

概要

Web サイト 花粉対策特集 - Yahoo!特別企画 を Ruby + Mechanize でスクレイピングして花粉飛散予報を取得する。

花粉飛散情報について

  • 花粉飛散予報は今日と明日の2日分
  • 沖縄県の花粉情報は無い
  • 飛散量には「少ない」「やや多い」「多い」「非常に多い」「飛散前」「飛散終了」「情報なし」などの文字列が入ると思われる

参考: 名古屋市中区の花粉情報 | 花粉症特集 - Yahoo!特別企画

kafunrank.png

Ruby によるサンプルコード

スクレイピングのためのライブラリとして mechanize を利用する。

require 'mechanize'

# 花粉飛散情報。
#
# データソース:
# 花粉対策特集 - Yahoo!特別企画 {https://kafun.yahoo.co.jp/}
class Kafun

  # 花粉飛散情報を取得する。
  #
  # @param pref_id [String]     JIS X 0401 都道府県コード
  # @param detail  [true/false] 詳細情報(2日分の花粉予報)を取得するか?
  # @return [Hash]
  def get(pref_id, detail=false)

    # URLの例
    # 北海道: https://kafun.yahoo.co.jp/weather/1/ ← 「01」じゃなくて「1」
    # 愛知県: https://kafun.yahoo.co.jp/weather/23/
    # 沖縄県のデータは無し
    # 都道府県コードが「01」で来ても「1」になるように to_i
    url = "https://kafun.yahoo.co.jp/weather/#{pref_id.to_i}/"

    agent = Mechanize.new
    page  = agent.get(url)

    date = page.search('.date').inner_text
    area = page.search('.dataBox__areaName a')
    data = page.search('.dataBox__pollenData .text')
    kind = page.search('.dataBox__pollenKind .text')

    area_list = []
    area.each_with_index do |e, i|
      area_list << { # 地域毎にデータを持つ構造に
        :area => e.inner_text, # 地域名
        :url  => "https:#{e[:href]}", # URL
        :data => [{ # 花粉飛散情報(日付別データの配列)
          :date => date, # 日付
          :rank => data[i].inner_text, # 飛散量
          :kind => kind[i].inner_text # 種類
        }]
      }
    end

    if detail
      detail_area_list = []
      area_list.each do |e|
        # 2日分の花粉飛散情報を取得
        detail_area_list << get_detail(e[:url], e[:area])
      end
      detail_area_list
    else
      # 1日分の花粉飛散情報を返す
      area_list
    end
  end

  private

  def get_detail(url, area)

    agent = Mechanize.new
    page  = agent.get(url)

    date = page.search('.dataBox__date')
    data = page.search('.dataBox__pollenData .text')
    kind = page.search('.dataBox__pollenData .text__kind')

    list = [] # 花粉飛散情報(日付別データの配列)
    date.each_with_index do |e, i|
      list << {
        :date => e.inner_text, # 日付
        :rank => data[i].inner_text, # 飛散量
        :kind => kind[i].inner_text # 種類
      }
    end

    {
      :area => area, # 地域名
      :url  => url, # URL
      :data => list # 花粉飛散情報(日付別データの配列)
    }
  end
end

puts '愛知県(都道府県コードは23)の花粉飛散情報を取得する(1日分)'
pp Kafun.new.get('23')
puts

puts '愛知県(都道府県コードは23)の花粉飛散情報を取得する(2日分)'
pp Kafun.new.get('23', true)
puts

サンプルコードの実行結果

愛知県(都道府県コードは23)の花粉飛散情報を取得する(1日分)
[{:area=>"名古屋市中区",
  :url=>"https://kafun.yahoo.co.jp/weather/23/23106/",
  :data=>[{:date=>"1月31日", :rank=>"飛散前", :kind=>"スギ花粉中心"}]},
 {:area=>"豊橋市",
  :url=>"https://kafun.yahoo.co.jp/weather/23/23201/",
  :data=>[{:date=>"1月31日", :rank=>"飛散前", :kind=>"スギ花粉中心"}]},
 {:area=>"岡崎市",
  :url=>"https://kafun.yahoo.co.jp/weather/23/23202/",
  :data=>[{:date=>"1月31日", :rank=>"飛散前", :kind=>"スギ花粉中心"}]},
 {:area=>"設楽町",
  :url=>"https://kafun.yahoo.co.jp/weather/23/23561/",
  :data=>[{:date=>"1月31日", :rank=>"飛散前", :kind=>"スギ花粉中心"}]}]

愛知県(都道府県コードは23)の花粉飛散情報を取得する(2日分)
[{:area=>"名古屋市中区",
  :url=>"https://kafun.yahoo.co.jp/weather/23/23106/",
  :data=>
   [{:date=>"1/31(水)", :rank=>"飛散前", :kind=>"スギ花粉中心"},
    {:date=>"2/1(木)", :rank=>"少ない", :kind=>"スギ花粉中心"}]},
 {:area=>"豊橋市",
  :url=>"https://kafun.yahoo.co.jp/weather/23/23201/",
  :data=>
   [{:date=>"1/31(水)", :rank=>"飛散前", :kind=>"スギ花粉中心"},
    {:date=>"2/1(木)", :rank=>"少ない", :kind=>"スギ花粉中心"}]},
 {:area=>"岡崎市",
  :url=>"https://kafun.yahoo.co.jp/weather/23/23202/",
  :data=>
   [{:date=>"1/31(水)", :rank=>"飛散前", :kind=>"スギ花粉中心"},
    {:date=>"2/1(木)", :rank=>"少ない", :kind=>"スギ花粉中心"}]},
 {:area=>"設楽町",
  :url=>"https://kafun.yahoo.co.jp/weather/23/23561/",
  :data=>
   [{:date=>"1/31(水)", :rank=>"飛散前", :kind=>"スギ花粉中心"},
    {:date=>"2/1(木)", :rank=>"少ない", :kind=>"スギ花粉中心"}]}]

参考資料