スキャンした電子書籍を{ISBN}.pdfという名前で溜め込んでおいたら、あとから検索性が悪くて絶望した。一覧ページを作るために、「ISBN 検索 API」でググったところ、Amazonと楽天が有力候補(…というかそれ以外にほとんど存在しない)らしい。

普段から使っていることだしAmazonでいいか…と使ってみたら、いろいろやることがあったので手順をメモっておく。

API開発者登録をする

開発者登録には米国amazon.comのアカウントが必要だ。私は以前DVDを買ったときのがあったのでそれを使ったが、持ってない人は取得しておこう。

アカウントが用意できたら、使いたい国に開発者登録をする。プログラミングガイドURLがまとまっているので、登録したい国(日本ならここ)に、_amazon.comのアカウントで_ログインする。

  • Website or Application Description
    • APIを利用するアプリケーションもしくはWebサイトの概要を記入する
  • Check here to indicate …
    • Amazon.co.jp Product Advertising API ライセンス契約を読み、同意したらチェックする
  • Security Check
    • 画像で表示された読みにくい英数字を入力する

すべて入力が終わると完了画面が表示されメールが届くので、メールのリンクからAccess Key IDを取得する。私はログインしたら2009年に作成したキーがあったのでそれを再利用したのだが、当時何を作る気だったのかはまるで覚えていない。

アソシエイトプログラムに登録して鍵ペアを取得すると世界各国のProduct Advertising APIにリクエストを送れるようになるそうだが、ここは省略。

APIにリクエストを投げてみる

ASINで一つの商品の情報を取得するには、ItemLookupというオペレーションにリクエストする。サンプル通りリクエストを組み立ててみると…

http://ecs.amazonaws.com/onca/xml?Service=AWSECommerceService&
AWSAccessKeyId={ACCESS KEY ID}&
Operation=ItemLookup&
ItemId=9784048687157
<?xml version="1.0"?>
<ItemLookupErrorResponse xmlns="http://ecs.amazonaws.com/doc/2005-10-05/">
  <Error>
    <Code>MissingParameter</Code>
    <Message>The request must contain the parameter Signature.</Message>
  </Error>
  <RequestID>********-****-****-****-************</RequestID>
</ItemLookupErrorResponse>

…あれ?

荒技「エラーメッセージをそのままググる」でヒットするのがこちらHMAC-SHA認証が必要だそうだ。

実際にクエリを構築するサンプルはこの辺に。

ruby-aaws

理屈はわかったので、実装は既存のものを使うことにする。今回は車輪の再発明はしなくてもいいだろう。ググったら「ruby-aaws」がヒットしたのでこれを使う。

install

インストールと使い方はこちらを参考に。rubygems.orgに最新バージョンがあがっていないので、本家配布元からgemパッケージを落としてきてインストールする。

% wget http://caliban.org/files/ruby/ruby-aaws-0.8.1.gem
% gem install ruby-aaws-0.8.1 --local

ruby-awsという紛らわしい名前のrubygemsもあるので注意。こちらはAmazon Web Servicesの操作をするものなので、今回は関係ない。

ドキュメントはあるにはあるが、あまりちゃんと書かれていないので若干手探りが必要だった。

.amazonrc

アクセスに必要な情報は.amazonrcファイルに書き込んでおく。/etc/.amazonrcや~/.amazonrcに書くのが定石だが、今回はアプリケーション内に閉じておきたいので、こちらを参考に…

ENV['AMAZONRCDIR']  = '/path/to/application_dir'
ENV['AMAZONRCFILE'] = '.amazonrc'

…とかして位置を指定してやる。中身はこんな感じ。

key_id = 'XXXXX'
secret_key_id = 'XXXXX'
associate = 'XXXXX'
cache = false
locale = 'jp'
encoding = 'utf-8'
usage

今回はスキャンした本のPDF(ファイル名はISBNになっている)を整理したいので…

  • オペレーション「ItemLookup」を使う
  • ISBNで検索する

という方向で実装した。こちらが大変参考になった。

1件検索
require 'amazon/aws'
require 'amazon/aws/search'
include Amazon::AWS

il = ItemLookup.new('ISBN', ItemId: '9784048687157', SearchIndex: 'Books')
request  = Search::Request.new
response = request.search il

XMLで返ってきたレスポンスにアクセスする手段がruby-aawsによって用意されている(Amazon::AWS::AWSArray)。propertiesでプロパティの一覧が取得でき、プロパティ名で値を取得する。XMLがベースなのでネストしていることもある。

item = response.item_lookup_response.items.item
item.properties
# => ["asin", "detail_page_url", "item_links", "sales_rank", "small_image", "medium_image", "large_image", "image_sets", "item_attributes", "offer_summary", "offers", "similar_products", "browse_nodes"]
item.item_attributes.title
# => [メタプログラミングRuby]
複数検索

ItemLookup、ItemSearchなどのオペレーションを配列に入れてMultipoeOperationに渡すと、複数のオペレーションを同時に渡すことができる。

asins = ['9784274065972',
         '9784756145482',
         # '9784798023809',
        ]

operations = asins.map do |asin|
  il = ItemLookup.new('ISBN', ItemId: asin, SearchIndex: 'Books')
  il
end

multiple_operation = MultipleOperation.new operations
request = Search::Request.new
result  = request.search multiple_operation, :ALL_PAGES

result.item_lookup_response.items[].item.item_attributes.title
# => [ハッカーと画家 コンピュータ時代の創造者たち]
result.item_lookup_response.items[1].item.item_attributes.title
# => [Winnyの技術]

ただし…

Amazon::AWS::Error::ExceededMaxBatchRequestsPerOperation: オペレーションごとのバッチリクエスト数の上限を超えました。1つ のオペレーションに入れられるバッチリクエスト数は、最大2です。

という制限もあるので注意しよう。

ResponseGroup

オペレーションのresponse_groupプロパティにResponseGroupオブジェクトを渡すと、取得する内容を指定することができる。

il = ItemLookup.new('ISBN', ItemId: '9784798023809', SearchIndex: 'Books')
il.response_group = ResponseGroup.new('ItemAttributes,Images')
request = Search::Request.new
result  = request.search il
item = response.item_lookup_response.items.item
item.properties
# => ["asin", "detail_page_url", "item_links", "small_image", "medium_image", "large_image", "image_sets", "item_attributes"]

どう指定すると何が返ってくるかはこちらを参照。

まとめ

これでAmazonからISBNで情報を取得できるようになった。あとは一覧ページを自動生成するためにせっせと頑張るだけになったので、今日はこの辺にしておこう。アプリケーションの形になったらGithubで公開予定だ。

Product Advertising API

https://images-na.ssl-images-amazon.com/images/G/09/associates/paapi/dg/index.html

SEO対策とか: Amazon Web サービス 仕様変更

http://seo-love.blogspot.com/2009/08/amazon-web.html

ruby-aaws | RubyGems.org | your community gem host

https://rubygems.org/gems/ruby-aaws

RDoc Documentation

http://www.caliban.org/ruby/ruby-aws/

Amazon Web Service を Ruby にて操作 – f-ikesanの日記

http://d.hatena.ne.jp/f-ikesan/20100505/1273075660

Railsでruby-aawsを使ってAmazon « cohakim's Weblog

http://cohakim.wordpress.com/2010/05/04/rails%E3%81%A7ruby-aaws%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6amazon/