わさっきhb

大学(教育研究)とか ,親馬鹿とか,和歌山とか,とか,とか.

Ruby/AWSで商品検索

当雑記では,isbn/asin記法を使って,本や商品にリンクしています.
この連休中に,商品情報の整理を自動化し,毎回ブラウザでAmazon.co.jpに行かなくても,検索したり,はてなでの表記を出したりできるよう,Rubyスクリプトを書いているところです.
Amazonへのアクセスを支援するライブラリには,AWS SDK for RubyRuby/AWSがあります.動かしてみたところ,Ruby/AWSを使えば,思うとおりに情報の取得ができることが分かりましたので,ここで紹介します.

準備

何をしたいのか,確認

何をしたいのかというと,雑記に書いた,ISBNやASINの値(10文字または13文字からなる文字列)をもとに,その商品情報を取得することです.
ISBNは,書籍の識別番号です.Amazonの商品を見る限り,10桁のISBNは,そのままASIN,すなわちAmazon独自の識別番号になるようです.13桁のISBNは,10桁化する(「978」とチェックデジットを取り除き,チェックデジットをつけ直す)とASINになります.一方,古書について,ISBNしかなく,ASINしか分かっていないものもあります.数は多くありませんが,書籍でないものをリンクしていることもあって,それもまた,asin記法を用いています.
少し調査したところ,単一の一連のコードによって,ISBNでもASINでも共通して,その情報を取得するのは,容易でないことが分かりました.そこで,

  • ISBNの値をもとに,書籍情報を取得する
  • ASINの値をもとに,商品情報を取得する

ためのRubyのコードを書くことにします.

irbで,ISBN検索

Amazon Web Service を Ruby にて操作 - f-ikesanの日記http://fujitaiju.com/blog/%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA/rubyrubyaws%E3%81%A7amazon%E3%81%AEproduct-advertising-api%E3%82%92%E6%93%8D%E4%BD%9C%E3%81%97%E3%81%A6%E3%81%BF%E3%81%9F%E5%AE%9F%E8%B7%B5%E7%B7%A8%EF%BC%88%EF%BC%91%EF%BC%89/を見て,自分なりにRubyスクリプトを書いてみたものの,エラーばかりです.
irbで,ステップごとに動かすことにします.まず,検索まではうまくいくようなコードを(悪戦苦闘して)作りました.

require "amazon/aws/search"
a = Amazon::AWS::ItemSearch.new("Books", {"Keywords" => "9784000295802"})
a.response_group = Amazon::AWS::ResponseGroup.new(:Medium)
req = Amazon::AWS::Search::Request.new
res = req.search(a)

irbを起動し,1行ずつ切り貼りして実行します.最後の行を実行すると,ずいぶんと表示されます.書籍情報が入っており,問い合わせはうまくいっています.
ここからなのですが,インスタンスメソッドpropertiesから,どんな子要素を持っているかを知ることができます.そして,その要素名をメソッドとして呼び出せば*1,子要素のオブジェクトを得ることができます.

irb(main):008:0> res.properties
=> ["__op__", "item_search_response"]
irb(main):009:0> res2 = res.item_search_response
(略)
irb(main):010:0> res2.properties
=> ["attrib", "operation_request", "items"]
irb(main):011:0> res3 = res2.items
(略)
irb(main):012:0> res3.properties
=> ["request", "total_results", "total_pages", "item"]
irb(main):013:0> res4 = res3.item
(略)
irb(main):014:0> res4.properties
=> ["asin", "detail_page_url", "item_links", "sales_rank", "small_image", "medium_image", "large_image", "image_sets", "item_attributes", "offer_summary"]
irb(main):016:0> res5 = res4.item_attributes
(略)
irb(main):017:0> res5.properties
=> ["author", "binding", "ean", "is_adult_product", "isbn", "label", "list_price", "manufacturer", "number_ofpages", "package_dimensions", "product_group", "product_type_name", "publication_date", "publisher", "studio", "title"]

子要素がないことは,以下に示すとおり,propertiesメソッドの結果が空かどうかで判断できます.それと,propertiesメソッドの戻り値は,Arrayに見えますが,実際にはAmazon::AWS::AWSArrayです.とはいえArrayのインスタンスメソッドは,問題なく使えるようです.

irb(main):018:0> res5.title
=> [かけ算には順序があるのか (岩波科学ライブラリー)]
irb(main):019:0> res5.title.properties
=> []
irb(main):020:0> res5.title.class
=> Amazon::AWS::AWSArray
irb(main):021:0> res5.class
=> Amazon::AWS::AWSArray
irb(main):022:0> res5.title.properties.empty?
=> true
irb(main):023:0> res5.properties.empty?
=> false

Amazon::AWS::AWSObjectによると,to_hによって,子要素をハッシュ化できるとのこと.試してみます.

irb(main):024:0> res5.to_h
=> {"author"=>高橋 誠, "binding"=>単行本(ソフトカバー), "ean"=>9784000295802, "is_adult_product"=>0, "isbn"=>4000295802, "label"=>岩波書店, "list_price"=>amount = 1260
currency_code = JPY
formatted_price = ¥ 1,260
, "manufacturer"=>岩波書店, "number_ofpages"=>128, "package_dimensions"=>height = 55
length = 709
weight = 40
width = 512
, "product_group"=>Book, "product_type_name"=>ABIS_BOOK, "publication_date"=>2011-05-27, "publisher"=>岩波書店, "studio"=>岩波書店, "title"=>かけ算には順序があ るのか (岩波科学ライブラリー)}

list_priceとpackage_dimensionsにはさらに子要素があることが分かりますが,上の情報が得られれば十分でしょう.あと,13桁ISBNは,eanの値です.ASINはありませんが,res4.asin.to_sで求められます.

ASIN検索

ASINによる商品検索のためのコードは次のとおり.

require "amazon/aws/search"
a = Amazon::AWS::ItemLookup.new("ASIN", {"ItemId" => "B000J8KINM"})
a.response_group = Amazon::AWS::ResponseGroup.new(:Medium)
req = Amazon::AWS::Search::Request.new
res = req.search(a)
res2 = res.item_lookup_response
res3 = res2.items
res4 = res3.item
res5 = res4.item_attributes

先ほどとの違いは,ItemSearchからItemLookupへ(コンストラクタへ与える引数も異なります),そして,検索結果の直下がitem_search_responseからitem_lookup_responseになっている点です.ASINの値はres4.asin.to_sで,変わりません.書籍でも,書籍以外の商品でも,この方法で詳細を知ることができます.

Rubyスクリプト

スクリプト化しました.いつものように,gistに置いています*2

内部状態は保持しなくていいので,classではなくmoduleにしました.検索に失敗するときもあるため,begin〜rescueを入れて,戻り値はHashインスタンスとし,失敗したときは空Hashとしました.
今回も,Ruby 1.8/1.9/2.0(スナップショット)に対応しています.
一つくらい,雑記に入れていた「かけ算」ネタ以外の本を,検索してみますか…

$ ruby amazon-searcher.rb 9784798114330
label: 翔泳社
studio: 翔泳社
author: 開米 瑞浩
title: ネーミングの掟と極意 (エンジニア道場)
isbn: 4798114332
publication_date: 2007-11-06
number_ofpages: 216
product_group: Book
product_type_name: ABIS_BOOK
asin: 4798114332
package_quantity: 1
publisher: 翔泳社
manufacturer: 翔泳社
ean: 9784798114330
sku: F12TR0010539504
binding: 単行本(ソフトカバー)
package_dimensions:
        length = 819
        width = 591
        weight = 71
        height = 87
list_price:
        currency_code = JPY
        formatted_price = ¥ 2,394
        amount = 2394
[asin:4798114332]

*1:res.methodsを見ると,:item_search_responseは見当たりませんが,おそらくmethod_missingがうまく機能しているのでしょう.

*2:本エントリ公開のあと,スクリプトの出力部を少し書き換えました.