NaClの石飛です。

全国の様々な場所にライブを見に行くことが趣味です。 そんな時会場までの道順などは調べるのですが周辺の施設についてはあまり調べず、いざ会場まで行ってみるとコンビニがすぐ近くになくて困ることなどもあります。 そこで施設名を渡すと周辺施設の件数や名前をWebAPI呼び出しを通して返してくれるスクリプトを書いてみたので紹介します。

緯度経度の取得

まず、施設名から地図上の緯度経度を取得します。 これには、Geocoding API が提供しているAPIを利用します。

require 'open-uri'
require 'rexml/document'
require 'json'

geocoding_uri = "http://www.geocoding.jp/api/?#{URI.encode_www_form({q: ARGV.join(' ')})}"
location = REXML::Document.new(open(geocoding_uri).read).elements['result'].elements['coordinate']

あらかじめ必要なライブラリをrequireしておきます。

対象とする施設名はコマンドライン引数で渡すこととします。 このスクリプトでは入力出力共に文字コードはUTF-8を想定しています。 また、スペース区切りで名称を指定することで目的地を正確に指定できるようにします。 例えば「株式会社ネットワーク応用通信研究所」で検索した場合、松江本社と東京支社の2つの建物が該当しますが、このAPIでは東京支社の情報が返されます。「島根 株式会社ネットワーク応用通信研究所」とスペース区切りで指定すると松江本社の情報が返されます。

このAPIのレスポンスはXMLで返されます。

緯度と経度はそれぞれresults > coordinatelatlngという名前で設定されています。 ここで取得した緯度と経度は次に利用する周辺施設APIで使用します。

緯度経度を元に周辺施設を検索

周辺施設の検索にはGoogle Places API Web Serviceを利用します。

APIの利用には、あらかじめAPIキーの取得が必要です。 またこのAPIには 24時間あたりのリクエスト数は1000件 までという制限があります(それを超える場合はクレジットカード認証を行うことで24時間に15,000件に引き上げることもできます)。 リクエスト数はGoogle Developers Consoleより確認することができます。

place_types = {
  convenience_store: 'コンビニ',
  restaurant: '飲食店'
}
place_params = {
  key: APIKEY,
  location: "#{location.elements['lat'].text},#{location.elements['lng'].text}",
  radius: 300,
  types: place_types.keys.join('|'),
  language: 'ja'
}
place_uri = URI.parse("https://maps.googleapis.com/maps/api/place/nearbysearch/json?#{URI.encode_www_form(place_params)}")

keyには取得したAPIキーを、locationには先程取得した緯度と経度をカンマ区切りで指定します。

radiusには指定したlocationから検索する範囲をメートルで指定します。ここでは例として300を指定します。

typesには取得する周辺施設のカテゴリを指定します。 指定可能な値はここから参照できます。 今回はコンビニと飲食店を対象とします。 あとからカテゴリごとに出力する際日本語で表示したいため、place_typesというハッシュに日本語とセットで値を設定しておきます。 types|区切りで複数指定することが可能です。

languageには検索結果を取得する言語を指定します。

結果をカテゴリごとにまとめる

上記で指定した条件を元にAPIを呼び出します。

results = {}
JSON.parse(open(place_uri).read)['results'].each do |result|
  place_types.keys.each do |type|
    if result['types'].include?(type.to_s)
      results[type] ||= []
      results[type] << result
    end
  end
end

こちらのAPIのレスポンスはJSONで返されます。

検索結果のresults配列に周辺施設の情報が1件ずつ格納されて返されます。 どの種別に該当する建物であるかという情報をtypesという配列で持っているため指定した種別のどれに該当したのかを判定し種別ごとに施設情報を分類します。

place_types.each do |type, type_name|
  places = results[type]
  puts "#{type_name}: #{places ? places.count : 0}件"
  if places
    places.each do |place|
      puts "* #{place['name']}"
    end
  end
end

最後にカテゴリごとに取得した施設数と施設名を表示します。

実行例

$ ruby place_search.rb 島根 株式会社ネットワーク応用通信研究所
コンビニ: 2件
* ローソン 松江総合体育館前店
* ファミリーマート松江学園南店
飲食店: 9件
* CoCo壱番屋 松江学園通り店
* The伊太利屋garden
* かつふじ
* スパイス王国 カレーキング Curry King 松江店
* 拉麺屋神楽松江店
* スターレオ
* STAR LEO
* ナマステ・ガネーシャ松江店
* Indian Spice Curry

とりあえず今回は近くにどのような施設があるか把握することを目的としていたため最低限の情報のみ表示しています。 レスポンスにはその他にも周辺施設の位置情報やユーザーによる評価、写真等の情報も含まれていますので、さらなる絞込も行えます。

まとめ

今回はWebAPIで周辺施設検索のスクリプトを作成してみました。 その他にも最近は様々な便利WebAPIが提供されているためもっと活用していきたいと思いました。