当雑記では,isbn/asin記法を使って,本や商品にリンクしています.
この連休中に,商品情報の整理を自動化し,毎回ブラウザでAmazon.co.jpに行かなくても,検索したり,はてなでの表記を出したりできるよう,Rubyスクリプトを書いているところです.
Amazonへのアクセスを支援するライブラリには,AWS SDK for RubyとRuby/AWSがあります.動かしてみたところ,Ruby/AWSを使えば,思うとおりに情報の取得ができることが分かりましたので,ここで紹介します.
準備
- http://aws.amazon.com/jp/から,AWS (Amazon Web Services)のアカウントを取得します.途中で電話認証がありました.画面に出ている4桁の認証番号を押すのでは失敗し,代わりに,受話器で言ってみると,少しの音声認識の時間ののち,成功しました.
- シェルで,gem install ruby-aawsを実行し,ライブラリを導入します.
- ~/.amazonrcというファイルを作ります.http://fujitaiju.com/blog/%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA/rubyaws%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%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E7%B7%A8/に,例があります.このうち,key_idとsecret_key_idは,AWSのアカウントで知ることができます.「セキュリティ証明書」を選び,「アクセスキーID」の値が,key_idです.「シークレットアクセスキー」を表示させて出てくる値は,secret_key_idに書きます.associateの行は,Amazonアソシエイト(アフィリエイト)のアカウントを持っていなければ,書かなくていいでしょう.
何をしたいのか,確認
何をしたいのかというと,雑記に書いた,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]