慣れない言語に四苦八苦しながら(といいつつ、かなり楽しんでいる)、Amazon ECSからデータを引っ張ってくるクラスを書いてみた。
まだRubyに不慣れなので、かなりアレなコードだと思われるが、夢中になってるとブログに書くのも忘れるので、とりあえずのネタとして。
require 'net/http'
require 'cgi'
require 'rexml/document'
class AmazonEcs
attr_reader :error_code, :error_message
@@common_params = {
:Service => 'AWSECommerceService',
:AWSAccessKeyId => 'XXXXXXXXXXXXXXXXXXXX',
:Version => '2007-05-14',
:AssociateTag => 'xxxxxxxxxxx',
:Operation => 'ItemSearch',
:ResponseGroup => 'Medium,BrowseNodes'
};
def initialize(book)
@sw = SearchWord.new
@sw.set_by_book(book)
end
def item_search
h = {}
@@common_params.each do |key,val|
h[key] = val
end
if @sw.isbn.blank?
h[:SearchIndex] = 'Books'
h[:Title] = @sw.title unless @sw.title.blank?
h[:Author] = @sw.author unless @sw.author.blank?
h[:Keyword] = @sw.keyword unless @sw.keyword.blank?
@response_node_name = 'ItemSearchResponse'
else
h[:SearchIndex] = 'Books' if @sw.isbn.length > 10
h[:IdType] = 'ISBN' if @sw.isbn.length > 10
h[:Operation] = 'ItemLookup'
h[:ItemId] = @sw.isbn
@response_node_name = 'ItemLookupResponse'
end
url = mk_url(h)
@xml = aws_request(url)
if has_xml_error?()
return nil
end
first_ecs_book()
end
def mk_url(h)
# RESTで必要なパラメータをURL形式に変更
arr = []
h.each do |key,val|
arr << key.to_s + "=" + CGI::escape(val.to_s)
end
paramString = arr.join('&')
URI.parse("http://webservices.amazon.co.jp/onca/xml?" + paramString)
end
def aws_request(url)
return REXML::Document.new(Net::HTTP.get(url))
end
def has_xml_error?
# エラーチェック
xpath = "ItemSearchResponse/Items/Request/Errors/Error"
@xml.get_elements(xpath).each do |element|
@error_code = element.text('Code')
@error_message = element.text('Message')
return true;
end
return false;
end
def first_ecs_book
xpath = "#{@response_node_name}/Items/Item"
@xml.get_elements(xpath).each do |element|
ecs_book = EcsBook.new
ecs_book.asin = element.text('ASIN')
ecs_book.isbn = element.text('ItemAttributes/ISBN')
ecs_book.title = element.text('ItemAttributes/Title')
ecs_book.author = element.text('ItemAttributes/Author')
ecs_book.manufacturer = element.text('ItemAttributes/Manufacturer')
ecs_book.binding = element.text('ItemAttributes/Binding')
ecs_book.publication_date = element.text('ItemAttributes/PublicationDate')
ecs_book.small_image_url = element.text('SmallImage/URL')
ecs_book.medium_image_url = element.text('MediumImage/URL')
ecs_book.large_image_url = element.text('LargeImage/URL')
ecs_book.detail_page_url = element.text('DetailPageURL')
return ecs_book
end
nil
end
end
中で使われている、SearchWordとEcsBookというクラスはそれぞれ、画面からの検索情報を渡すためのプレースホルダー、およびAmazonECSからの結果を保持し、DBへ格納するためのActiveRecordです。
ISBNが指定されている場合は、優先してISBN検索をするようにしたのだが、最近買った本(具体的には泣き虫弱虫諸葛孔明第弐部)のISBNを入れてみたところ、うまくいかない。
この本はISBNが従来の10桁ではなく13桁になっている(詳しくはWikipediaを参照のこと)。
ISBNが11桁以上だったら、IdTypeパラメータをISBNに設定(このとき、SearchIndexパラメータも必要となる)すると、ItemLookupオペレーションが動くことを発見。ちなみに10桁のISBNは、ASINと一致なので、IdTypeはASIN、もしくは指定しない(=ASIN)である。ASINの場合、面倒だがSearchIndexパラメータが指定されると逆にエラーとなる。
APIドキュメントによると、JPではIdType=ISBNはサポートされてないことになっているが、使えるから良いか。
どうせなら10桁の時も、IdType=ISBNで取得させてくれれば楽だと思うのだが、そうはなっていない。