- 2007/09/12
- Ruby
今時というか、昔流行ったWeb2.0の目玉の一つはマッシュアップでしょ?ってことで、Yahoo!が公開している検索APIを使って、検索結果を取得するスクリプトを Ruby で組んでみた。Yahoo!では、API はすべて REST なので実装は非常に楽。 というわけで、続きます。
RESTとは
そもそも REST ってなんだよ的なところから始まっているので手に負えない。調べてみたら色々な意味を持たされているらしい。
REST は既存の Web アプリケーション(人間が使うサービス)だけではなく、いわゆる Web サービス(機械が使えるサービス)のためのアーキテクチャスタイルでもあります。いわゆる SOAP を使った Web サービスとはアーキテクチャが真っ向から対立するため、 REST と SOAP はしばしば対立軸で語られます。
ここでは、RESTについて深く言及はしないけれど、非常に参考になるリンクをあげておく。
まず、Yahoo!デベロッパーネットワークへ
なにをするにもとりあえずYahoo!デベロッパーネットワークのページへ。今回は、普通のYahoo!検索エンジンの検索結果を取得したいので、Yahoo!検索の API へ。
リクエスト方法は非常に簡単で
http://api.search.yahoo.co.jp/WebSearchService/V1/webSearch?appid=アプリケーションID&query=検索ワード
を持ってくるだけ。
他にも表示件数やページング、検索結果の抽出方法などオプションがあるが最低限必要なのは2つ。「アプリケーションID」と「検索ワード」だけ。アプリケーションIDはYahoo!デベロッパーネットワークの中で簡単に登録できるのであらかじめ登録しておこう。
URLをファイルとして開く
サーバ内部にあるファイルであれば
fp = open(FILENAME)
fp.each{|line|
...
}
で開けるのだけど、httpなどから始まるURLに関してはこのままでは開けない。ここは open-uri を使う必要がある。
open-uriの使い方
require 'open-uri'
open("http://blog.tofu-kun.org/") {|fp|
...
}
これを使って、Yahoo!検索のリクエストURIを指定してあげればXMLファイルを取得することが出来る。
open("http://api.search.yahoo.co.jp/WebSearchService/V1/webSearch?appid=xxx&query=ruby"){|fp|
fp.each{|line|
print line
}
}
これを実行すると、Rubyと検索した結果がXMLで返される。
XMLを解析する
XMLが返されたってXMLを解析できなきゃデータの持ち腐れ。RubyにはXMLの解析をしてくれる強力なモジュール REXML がある。正直僕はあまりXMLについて詳しくないので、あまりにも多機能で便利そうなモジュールなのだけど、今のところ基本的な解析にしか使っていない(これから本格的に使っていかなきゃ)。
REXMLを使う際に役立つリンク
この3つを流し読みすれば、とりあえず今回の目的は果たせそうだ。
REXMLの使い方
require "rexml/document"
xmlBody = <<EOM
<?xml version="1.0" encoding="EUC-JP"?>
<Diary>
<Page>
<Title>日記かきます</Title>
<Message>最近はニコニコ</Message>
</Page>
<Page>
<Title>日記やめます</Title>
<Message>ニコニコすぎる</Message>
</Page>
</Diary>
EOM
xml = REXML::Document.new xmlBody
print xml.root
#XMLツリー全体を表示
xml.elements.each("Diary/Page"){|line|
print '<li>' + Kconv.toeuc(line.elements["Title"].text) + '</li>'
#Diary -> Page の中にある Title のテキストを表示
}
こんなシンプルすぎるXMLなんて滅多にないと思うけど。
ちなみに、REXML の内部はすべて UTF-8 で記述されているので、UTF-8 以外の文字コードの XML を解析する場合は、きちんと XML にエンコードを指定してあげた上で、出力する際に文字コードを変更する必要がある。
とはいっても、だいたいのXMLファイルは UTF-8 でコーディングされているので、スクリプト側も UTF-8 に統一するか、出力する時に変換してあげれば大丈夫。
文字コードの変換
require 'kconv' Kconv.tojis(text) #text をJISへ Kconv.toeuc(text) #text をEUC-JPへ Kconv.tosjis(text) #text をShift_JISへ Kconv.toutf8(text) #text をUTF-8へ
URLエンコードをする
URIに検索キーワードを含めてアクセスするので、当然検索キーワードをURLエンコードしてあげる必要がある。記号抜き英字のみの検索にしぼるのなら必要はないが…。そんなのは現実的ではないので全部エンコードしちゃう。
require "cgi" textdata = CGI.escape(textdata)
と、非常に簡単。ただし、UTF-8 の状態でエンコードしないと意味がないので、あらかじめ EUC-JP から UTF-8 に変換してあげる。
require "cgi" textdata = CGI.escape(Kconv.toutf8(textdata))
Yahoo!からXMLを受け取ってみる
外部URIをファイルとして開く/XMLを解析する/文字コードを変換するの3つで今回の目的が果たせそうなので、合体して完成させてみる。
#!/usr/local/bin/ruby
#ライブラリ読み込み
require "cgi"
require 'open-uri'
require "rexml/document"
require 'kconv'
#ヘッダ出力
cgi = CGI.new
puts cgi.header(
"type" => "text/html",
"charset" => "EUC-JP"
)
#最大文字数(2byte文字だと半分)
MAXLEN = 50
#入力データが空でなければ格納
if cgi["textdata"] != "" then
#文字数チェック
if cgi["textdata"].size <= MAXLEN then
#検索キーワードをエンコード(EUC->UTF-8)
keyword = CGI.escape(Kconv.toutf8(cgi["textdata"]))
#検索結果を取得
xml = REXML::Document.new(open("http://api.search.yahoo.co.jp/WebSearchService/V1/webSearch?appid=xxxx&query=" + keyword + "&results=3"))
result = "<ul>"
xml.elements.each("ResultSet/Result") {|line|
result += '<li><a href="' + line.elements["Url"].text + '">' + Kconv.toeuc(line.elements["Title"].text) + '</a></li>'
}
result += "</ul>"
else
errorMsg = "<p><strong>文字数が#{MAXLEN}を超えています</strong></p>"
end
end
print <<EOM
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=EUC-JP">
<title>RubyでYahoo!検索APIを使って検索結果を表示してみる</title>
</head>
<body>
<h1>RubyでYahoo!検索APIを使って検索結果を表示してみる</h1>
<h2>検索したいキーワード</h2>
<form action="02.cgi" method="post">
<input type="text" name="textdata" value="">
<input type="submit" value="検索結果を表示">
</form>
#{errorMsg}
<h3>仕様</h3>
<ul>
<li>3位まで表示</li>
<li>検索ワードは全角25文字くらいまで</li>
</ul>
<h3>検索結果</h3>
#{result}
</body>
</html>
EOM
まとめ
今回は、外部のサービスを利用したスクリプトを作ってみた。作るだけなら今回のように簡単に構築できるが、これを公開し運営していくとなると、実はもっと実装しなければならない機能がある。
- APIの規約に違反していないかどうか(大前提)
- アクセス数に制限がある場合が多いので、キャッシュ機能など
- エラーが返ってきた時の処理
- 踏み台にならないための連続アクセス制限
なので、次回はそこら辺も踏まえた仕様で作ってみようと思う。
- Newer: PHPのopen_basedir設定:Pleskで管理されているサーバ
- Older: Rubyはじめました3:Ruby本を買いました。