会社が白金台に引っ越しました。外苑前と比べると人がすごく少なかったり、オフィスの隣には都内有数の森があったり、窓からその森が見えたり、僕がその窓際に座っていたり、座って作業していると半径10mに人が1人もいなかったり(前のオフィスは30人くらいいた)して、かなりいい感じです。
そんなカッチョいいオフィスで社会と会社と己のマニーのために働いている僕ですが、先日社長が"カッチョいいディスプレイを会社のフロントに置くから、そこでなんかやってよ"などとおっしゃってまして、ちょっとしたデモを作ることにしました。
何を書いたかというと、食べログの駅名検索で取得できるレストランをランダムでGoogle Earth上に表示するRuby scriptです。WindowsだとCOM APIとか言うのがあっていろいろやんちゃできるみたいなんですが、うちの社長は最近Macにこってるので無理です。apple script経由でGoogle Earth.appに動的にkmlをロードさせる感じで書きます。
earth.scpt:
# osascript ./earth.scpt 'Macintosh HD:Users:po:Desktop:doc.kml'
on run argv
set kml_path to item 1 of argv
tell application "/Applications/Google Earth.app"
#tell application "/Applications/Safari.app"
activate
open file kml_path
end tell
end run
で、rubyではtabelog apiを駅名で叩いて取得した情報をkmlに変換し、10秒ごとにランダムピックアップ後保存してearth.scptを叩いています
#!/usr/bin/ruby -Ku
require 'open-uri'
require 'cgi'
require 'rexml/document'
require 'rubygems'
require 'active_support'
require 'mechanize'
station = '白金台'
kml_path = '/Users/po/test/earth/tabelog.kml'
kml_input_path = "Macintosh HD#{kml_path.gsub(/\//, ':')}"
default_placemark_path = './placemarkDefault.yml'# kmlのdefault値読み込み
default_placemark = YAML.load_file(default_placemark_path)
class Hash
# kml化
def to_kml
self.to_xml(:root => 'Placemark').sub(/\n/, %!\n<kml xmlns="http://earth.google.com/kml/2.0">\n!).sub(/<\/Placemark>\n/, %!</Placemark>\n</kml>\n!)
end# うーんなんかまずそう まいっか
def dmerge(other)
me = self.dup
other.each do |k, v|
if v.is_a?(Hash)
me[k] = me[k].dmerge(v)
else
me[k] = v
end
end
me
end
end
def hash_by_item(e)
_r = {}
trans = {
:name => 'RestaurantName',
:category => 'Category',
:score => 'TotalScore',
:latitude => 'Latitude',
:longitude => 'Longitude',
:url => 'TabelogUrl'
}trans.each do |to, from|
_r[to] = e.elements[from].text
endr = {
:name => _r[:name],
:description => %|<a href="#{_r[:url]}">#{_r[:name]}</a> : #{_r[:category]}, (#{_r[:score]})|,
:LookAt => {
:latitude => _r[:latitude],
:longitude => _r[:longitude],
},
:Point => {
:coordinates => "#{_r[:longitude]},#{_r[:latitude]},20"
}
}
end
kmls = []
page = 1
items_per_page = 20
max_page = 1
while(page <= max_page) do
puts url = "http://api.tabelog.com/Ver1.1/RestaurantSearch/?ResultSet=large&Station=#{CGI.escape(station)}&PageNum=#{page}"
xml = REXML::Document.new open(url).read
max_page = (xml.elements['//NumOfResult'].text.to_f / items_per_page).ceilREXML::XPath.match(xml, '//Item').each do |e|
kmls << default_placemark.dmerge(hash_by_item(e)).to_kml
endpage += 1
sleep 5
endwhile(true) do
File.open(kml_path, "wb"){|f| f.write kmls[rand(kmls.size)]}
`osascript ./earth.scpt '#{kml_input_path}'`
sleep 10
end
ActiveSupportのHash.to_xmlがいい感じだったので使いました。あとkmlのデフォルト値を外部にymlで持ってます。
placemarkDefault.yml
これと取得した情報をdeep_merge?する感じ。
---
:Point:
:extrude: "1"
:altitudeMode: relativeToGround
:coordinates: 0.0,0.0,0
:visibility: "1"
:name: ""
:Style:
:IconStyle:
:Icon:
:h: "32"
:w: "32"
:y: "160"
:x: "96"
:href: root://icons/palette-3.png
:description: ""
:LookAt:
:latitude: "0.0"
:tilt: "60.0"
:longitude: "0.0"
:range: "300.0"
可視化としてはお店/料理の画像が表示されてなかったりしてかなりダメですけれど、やっときたかったのはkmlの生成とそのロードなので、ま良いかなと。あとあんまりkml仕様書真面目に読んでない。