フナミタカオです
リクルートWebサービスが公開されて10日ほど、たちましたが、皆様もう触られましたでしょうか?
マッシュアップアワード3のネタとしても、ぜひ、ためしてみてくださいね
今回は、海外旅行情報:エイビーロードWebサービスのサンプルコードをRubyでつくってみました。
Ruby1.8.xが前提ですが、FTPしてもらえれば、動くようになっていると思います。
さくらインターネットと、DreamHostで確認済みです。
実は、PHPでも、サンプルコードを書き始めていたのですが、簡単なスクリプトから、逸脱して、気がつくと、俺プチフレームワークを作り始めていました。
なれないげんごだと、力加減がわからず、つい作りこみすぎてしまったりするものです。
僕にとっては、一番のお気に入りのRubyで再実装してみました。
簡単なところから初めて、最終的には、クラス化や、Ruby On Railsのプラグイン化も目指しつつ、少しづく充実してゆく予定です。
今回は、キーワードで、ツアー一覧を検索するという簡単なものですが、XMLから、検索結果を取り出す方法や、ページングの処理、ERBを使ったテンプレート等参考にしていただけるとうれしいです。
リクルートWebサービスが公開されて10日ほど、たちましたが、皆様もう触られましたでしょうか?
マッシュアップアワード3のネタとしても、ぜひ、ためしてみてくださいね
今回は、海外旅行情報:エイビーロードWebサービスのサンプルコードをRubyでつくってみました。
Ruby1.8.xが前提ですが、FTPしてもらえれば、動くようになっていると思います。
さくらインターネットと、DreamHostで確認済みです。
実は、PHPでも、サンプルコードを書き始めていたのですが、簡単なスクリプトから、逸脱して、気がつくと、俺プチフレームワークを作り始めていました。
なれないげんごだと、力加減がわからず、つい作りこみすぎてしまったりするものです。
僕にとっては、一番のお気に入りのRubyで再実装してみました。
簡単なところから初めて、最終的には、クラス化や、Ruby On Railsのプラグイン化も目指しつつ、少しづく充実してゆく予定です。
今回は、キーワードで、ツアー一覧を検索するという簡単なものですが、XMLから、検索結果を取り出す方法や、ページングの処理、ERBを使ったテンプレート等参考にしていただけるとうれしいです。
機能概要
DreamHost上での動作サンプル|さくらインターネット上での動作サンプル(←サンプルは外部サイトへのリンクとなります)キーワードと、出発月のしてのみができるという、シンプルなつくりですが、最低限のページングもつけました。
XMLで呼び出す
Ruby1.8以上であれば、REXMLが標準添付されています。エイビーロードWebサービスは、xmlだけでなく、json、jsonpフォーマットでも受け取れます。jsonのほうが、rubyのハッシュにするのは、やりやすいし、転送されるファイルも小さいので、できればjsonを選択したい。
ただ、jsonを使うとなると、未インストールの場合はインストールが必要になるので、ここは、いったんXMLをつかたサンプルを書いてみました
Webサービスにクエリを投げているのが、44~48行目付近の以下のコード
uri = "#{API}?#{query.to_q}" #ここに、リクエストのURLが入る
result = nil
# xml読み込み
open(uri) do |f|
obj = REXML::Document.new(f.read) #f.readで一気に読み込んでオブジェクト化
result = obj.elements['results'] #results要素を取り出した。
end
↑のようにXMLからresultのオブジェクトを生成した各要素はelementsメソッドで取得できます。
result.elements['results_available'].text.to_iresults_availableにて、検索条件の全ヒット件数が戻る。
textをつけないと、要素タグが、ついたまま戻ってくるの注意
print result.elements['results_available'] は
<results_available>18</results_available>のように、要素名までかえす。
textメソッドを、いちいち書かなくてはいかないので、ちょっと面倒。
複数要素の取り出し
ツアーの検索結果には、複数のツアーが含まれる可能性がある。(もちろん0件になる場合もあるが) 各ツアーにを読み出すために、ループをまわすが記述は以下のようになる。
result.elements.each('tour') do |tour|
tour.elements['id']
end
idはtour.elements['id']で取り出せるので、複数項目を
result.elements['tour'].each do |tour|
......
end
と書いても、動きそうだが、これはうまくいかない。いづれにしても、REXMLのDomになっているので、単純なハッシュではない。ppでダンプしても、全体構造が見えなくて、ちょっと、わかりづらい。
このあたりのデータのハンドリングはjsonのほうが、断然、やりやすい。とはいえ、通常はクラスになっているのがよろしいので、XMLとJsonの差異は実行時のパフォーマンスで効いてくるかもしれない
XMLのほうが、閉じタグがあって、どうしても同じ情報量をあらわすときのバイト数が、Jsonよりも多くなる。
XPathも使える
ツアーの出発地名はtour.elements['dept_city/name'].textとXPathを指定しても可能。
テンプレートはERBで
ロジックとデザインの分離のためにERBを利用しています。71行目あたりからのヒアドキュメントが、テンプレートです。
今回はサンプルとして1ファイルに収めたかったので、テンプレートも一緒に書きましたが、本来は、別ファイルに書いていくべきだと思います。
テンプレートを別にすることで、テンプレートはDreamweaverでの編集とかがやりやすくなります。
Ruby on RailsもERBを使っていますが、かなり拡張されている。今回はRuby on railsのライブラリは使っていないので、3桁ごとに”,”を打つロジックは、別途メソッドを追加しました。(ただし、数値に限らず、右から3桁づつのところにカンマを挿入するだけです)
String#to_priceです。
class String
def to_price
temp = self.reverse
# temp.scan(/.{3}/).join(',').reverse
#↑すみません、これはまちがいでした。これだと50000が000になってしまいます。
temp.scan(/.?.?./).join(',').reverse
end
end
文字列をリバースして、3文字づつの配列にし、カンマでジョインして、再度リバースしています。
今回は、スタイルシートは用意していませんが、最終的な画面デザインは、できるだけCSSに任せてゆくつもりです。サーバーで動かしてみる
さくらのレンタルサーバーと、DreamHostで動作確認しました。ただし、1行目のrubyパスは、環境によって異なるので、適宜変更してください。
さくらの場合
#!/usr/local/bin/rubyDreamHostの場合
#!/usr/bin/rubyロリポップでは、動作時に500のエラーになります。(原因調査中ですがTelnetできないので、思案中、rubyのバージョンかなあ...)
インストール手順
- ファイルをダウンロード
- 1行目のRubyのバスの確認・必要なら修正
- 35行目のAPIキーの設定
- 以上の修正後、
- FTPでアップロード
- 実行権限の付与
- ブラウザから実行
全ソース
#!/usr/local/bin/ruby $LOAD_PATH << "#{File.dirname(__FILE__)}/../lib" require 'open-uri' require 'erb' require 'cgi' require 'rexml/document' require 'date' require 'pp' class Hash def to_q() query = [] self.each do |key,value| query << "#{key}=#{ERB::Util.u(value.to_s)}" end query_str = query.join("&") end end class String def to_price temp = self.reverse temp.scan(/.?.?./).join(',').reverse end end API = 'http://webservice.recruit.co.jp/ab-road/tour/v1/' MY_API_KEY = 'guest'#<-ここに、自分のAPIキーを入力してください cgi = CGI.new query = cgi.params query['key'] = MY_API_KEY #apiキーのセット query['format'] = 'xml' #formatをxmlに固定 query['count'] = 10 #query['ym'] = (Date.today >> 1).month if query['ym'] == 0 uri = "#{API}?#{query.to_q}" result = nil # xml読み込み open(uri) do |f| obj = REXML::Document.new(f.read) result = obj.elements['results'] end #ページングの計算 page = nil page_query = query.dup page_query.delete 'start' page_query = page_query.to_q if result.elements['results_available'] && result.elements['results_available'].text.to_i > 0 page = {} page['current'] = (result.elements['results_start'].text.to_i/query['count']).truncate page['first'] = 0 page['prev'] = page['current'] - 1 page['prev'] = page['first'] if page['prev'] < page['first'] page['last'] = (result.elements['results_available'].text.to_i/query['count']).truncate page['next'] = page['current'] + 1 page['next'] = page['last'] if page['next'] > page['last'] end query.delete 'key' #キーは削除する #以下テンプレート #Ruby on Railsでも、おなじみのERBを利用しています。 script = <<EOF <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title><%= query.to_q %></title> </head> <body style="margin:10pt;font-size:0.8em"> <p><a href="http://webservice.recruit.co.jp"><img src="http://webservice.recruit.co.jp/banner/abroad-s.gif" alt="エイビーロードWebサービス" width="135" height="17" border="0" title="エイビーロードWebサービス"></a></p> <form action="" method="get"> フリーワード:<input type="Text" name="keyword" value="#{query['keyword']}"> 出発月: <select name="ym"> <%- d = Date.today -%> <option value="" >指定なし</option> <%- 12.times do |i| -%> <%- d = d >> 1 -%> <%- if query['ym'].to_s == d.month.to_s -%> <option value="<%= d.month %>" selected="selected"><%= d.month %>月</option> <%- else -%> <option value="<%= d.month %>" ><%= d.month %>月</option> <%- end -%> <%- end -%> </select> <input type="submit"> </form> <%- if result.elements['error'] -%> <ol> <%- result.elements.each('error') do |error| -%> <li style="color:red">エラー:<%= error.elements['message'].text %></li> <%- end -%> </ol> <%- elsif result.elements['results_available'].text.to_i == 0 %> <p>検索で一致するコースは見つかりませんでした。</p> <%- else -%> <p>検索結果:<%= result.elements['results_available'].text %>件(<%= result.elements['results_start'].text %>~<%= result.elements['results_start'].text.to_i+result.elements['results_returned'].text.to_i-1 %>件目)<br /> <%- if page -%> <a href="?#{page_query}&start=<%= page['first']*query['count']+1 %>" ><<先頭</a> <a href="?#{page_query}&start=<%= page['prev'] *query['count']+1 %>" ><前</a> [ <%= page['current']+1 %> ] <a href="?#{page_query}&start=<%= page['next'] *query['count']+1 %>" >次></a> <a href="?#{page_query}&start=<%= page['last'] *query['count']+1 %>" >最後>></a> <%- end -%> </p> <%- result.elements.each('tour') do |tour| -%> <div style="margin:10pt 0;"> <%= tour.elements['dept_city/name'].text %>発:<%= tour.elements['term'].text %>日間 旅行代金:<%= tour.elements['price/min'].text.to_price %>円~<%= tour.elements['price/max'].text.to_price %>円<br/> <a href="<%= tour.elements['urls/pc'].text%>"><%= tour.elements['title'].text -%></a><br /> 訪問地:<%= tour.elements['city_summary'].text %><br /> ブランド:<%= tour.elements['brand/name'].text %><br /> </div> <%- end -%> <%- end -%> <div style="margin:10pt 0"> <pre><%= "#{API}?key=[API KEY]&" << query.to_q %></pre> </div> </body> </html> EOF #書き出し e = ERB.new(script,nil,'-') print "Content-Type: text/html; charset=UTF-8\n\n" e.run
今回のコーディングで参考にしたページ
逆引きRuby 日付と時刻:翌月等、何ヶ月かの月を求める方法標準添付ライブラリ紹介 【第 10 回】 ERB
3桁ごとにカンマを入れる
AB-ROAD エイビーロード | APIリファレンス | リクルートWEBサービス







コメント (1)
なぜか僕の環境だと
result.elements['results_available'].text
とするとエラーが出ますね。
rdeでルビーバージョン1.8.6なんでけど。
投稿者: 匿名 | 2008年12月02日 03:08
日時: 2008年12月02日 03:08