GoogleスプレッドシートをWebスクレイピングしてみた
http://ittemia.jp/zensen/themes/view/39
ここで駅名しりとりをしていて、私も機会があれば投稿したいなぁと、列車で移動中とかに時々チェックしている。一回出た駅は使えないルールなので、取りに行けそうだと思っても、今までに出てないか気になる事がある。
http://spreadsheets.google.com/pub?key=pS_Iu-LTUb202uc2p8lQoOw&gid=1
このGoogleスプレッドシートで、今までに出た駅名一覧が登録されているのだけど、携帯電話から見に行くには、フルブラウザを使わなくてはいけなかったりで、なかなか難しい。
このGoogleスプレッドシートはHTMLで表現されているので、Webスクレイピングして必要な情報だけ抜き出せば、携帯電話から見れる形に変換するのも簡単そう。そう思いついたので、さっそくやってみた。
最初はHpricotでHTML解析しようと思ったのだけど、どうもHTMLの構造がスプレッドシートの行単位で抜き出しにくいので、正規表現で行単位でマッチさせて、必要な値を取り出すことにした。
コード的には、こんな感じ。
url = 'http://spreadsheets.google.com/pub?key=pS_Iu-LTUb202uc2p8lQoOw&gid=0' doc = open(url).read @list = '' rows = doc.scan( %r|<tr><td class=hd><p style='height:16px;'>.</td><td class='s0 ' >[^<]+<td class='s1 ' >[^<]+<td class='s1 ' >[^<]+<td class='s1 ' >[^<]+|) rows.each do |row| m = row.match( %r|<td class='s0 ' >([^<]+)<td class='s1 ' >([^<]+)<td class='s1 ' >([^<]+)<td class='s1 ' >([^<]+)|) if m #@listに、駅名表示用HTMLを出力 @list << "#{m[1]}:#{m[2]}(#{m[3]})@#{m[4]}<br />" doc = m.post_match end end
で、かな順のシートのページも合わせて、ramazeを使ってWebアプリ化。
コードはこんな感じ。ramazeだと、これくらいのものなら1つのファイルで書けちゃうのが良いな。
require 'ramaze' require 'open-uri' class ShiritoriController < Ramaze::Controller engine :Erubis map '/' layout :layout INDEX = %w[あ か さ た な は ま や ら わ] def index sort end def history url = 'http://spreadsheets.google.com/pub?key=pS_Iu-LTUb202uc2p8lQoOw&gid=0' doc = open(url).read @list = '' rows = doc.scan(%r|<tr><td class=hd><p style='height:16px;'>.</td><td class='s0 ' >[^<]+<td class='s1 ' >[^<]+<td class='s1 ' >[^<]+<td class='s1 ' >[^<]+|) rows.each do |row| m = row.match(%r|<td class='s0 ' >([^<]+)<td class='s1 ' >([^<]+)<td class='s1 ' >([^<]+)<td class='s1 ' >([^<]+)|) if m #駅名表示 @list << "#{m[1]}:#{m[2]}(#{m[3]})@#{m[4]}<br />" doc = m.post_match end end return %{ 履歴順 | <a href="<%= Rs(:sort) %>">かな順</a><br /> <%= @list %> } end def sort url = 'http://spreadsheets.google.com/pub?key=pS_Iu-LTUb202uc2p8lQoOw&gid=1' doc = open(url).read m = true @list = '' rows = doc.scan(%r|<tr><td class=hd><p style='height:16px;'>.</td><td class='s\d ' >[^<]*<td class='s\d ' >[^<]*<td class='s\d ' >[^<]*<td class='s\d ' >[^<]*|) rows.each do |row| # インデックス表示 m = row.match(%r|<tr><td class=hd><p style='height:16px;'>.</td><td class='s0 ' ><td class='s1 ' >([^<]+)<td class='s2 ' ><td class='s2 ' >|) if m index_no = INDEX.index(m[1]) @list << %!<a href="#index" name="i#{index_no}">●#{m[1]}</a><br />! if index_no end # 駅名表示 m = row.match(%r|<tr><td class=hd><p style='height:16px;'>.</td><td class='s3 ' >([^<]+)<td class='s4 ' >([^<]+)<td class='s4 ' >([^<]+)<td class='s4 ' >([^<]+)|) if m @list << "#{m[1]}:#{m[2]}(#{m[3]})@#{m[4]}<br />" end end @index = INDEX return %{ <a href="<%= Rs(:history) %>">履歴順</a> | かな順<br /> <a name="index">></a> <% @index.each_index do |i| %> <a href="#i<%= i %>"><%== @index[i] %></a> <% end %><br /> <%= @list %> } end def layout %{ <?xml version="1.0" encoding="UTF-8"?> <html> <head> <title>駅名しりとり 駅名一覧</title> </head> <body> <h1>全国駅名しりとりラリー 携帯用駅名一覧</h1> <%= @content %> </body> </html> } end end Ramaze.start
そして、Webに公開。
http://api.xii.jp/ittemia/shiritori/
単純なHTMLしか使ってないとは言え、携帯から見えるHTMLなのか不安だったが、とりあえず表示はできるっぽい。
と、ここまでやって気づいたが、GoogleならスプレッドシートのWeb APIを公開していてもおかしくない。
少し探してみたら、案の定公開していた。
http://code.google.com/apis/spreadsheets/overview.html
うーむ、こっちを使った方が良かったのかも。