Blank?=False

ゆるゆる仕事したいフリーランスエンジニアの記事

RubyでAmazonのAPIを使ってKindle Unlimited本の一覧を取得する。

f:id:stonebeach-dakar:20161127221628j:plain

AmazonKindle Unlimitedに関係したWebアプリを作るか。
と、ふと思いついたので、とりあえずKindle Unlitmitedの一覧を取得しなきゃな、AmazonだしなんかAPIあるだろ、という見切り発車でスタート。

ちょっと色々苦労したので書いていきます。

ソースコード

Gistにあげました。
Amazonのアソシエイトタグ、AWSのアクセスキーIDとシークレットキーはご自分のを入力して使ってください。

RubyでAmazon APIを使ってKindle Unlimited本の一覧を取得

開発環境の準備

まずはAPIキーを取得

もしかしたらある意味面倒臭いAPIキーの取得。
AmazonアソシエイトのIDとAWSのID、両方必要になります。

もともとアソシエイトのIDは持っていたので、AWSのIDだけ取得するだけで済みました。
今は多少画面が代わってますが、だいたい↓を参考にすればできました。
「Amazon API」の使い方を紹介します!最安値やランキング取得できるよ①-アソシエイトID(タグ)登録編- - ぱんぶろ

Gem [Amazon-Ecs]をインストール

APIを直接記述するのは大変そうなので、何か便利なGemかないかなとGoogle先生に聞いてみたらドンピシャなGemがありました。
github.com

下を参考にインストール。 take-she12.hatenablog.com

苦労したこと

公式ドキュメントにKindleそのものの情報がない

公式ドキュメント、2010年以降一切更新されていないようで、Kindleストアそのものの情報もありません。
なのであまりアテにできず、トライアンドエラーの繰り返しになりました。

Product Advertising API
AmazonにあるKindle本を検索するためには、ItemSearchを使わないといけないわけですが、そのItemSearchは大まかな分類となるSearchIndexの入力が必須となっています。
ただ、そのSearchIndexの一覧を公式ドキュメントでみても、Kindleはありません。そりゃ日本にKindleが上陸したのって2012年だし。

結局、ヤマカンでKindleと設定してみたらやっぱりエラー。そのメッセージで何を入れれば良いのか教えてくれました。

SearchIndexに指定した値は無効です。[ 'All','Beauty','Grocery','Industrial','PetSupplies','OfficeProducts','CreditCards',
'Electronics','Watches','Jewelry','MobileApps','Shoes','KindleStore','Automotive','MusicalInstruments','GiftCards','Toys',
'VideoDownload','SportingGoods','PCHardware','Books','VHS','MP3Downloads','Baby','MusicTracks','Hobbies','VideoGames','ForeignBooks','Apparel',
'Marketplace','DVD','HomeImprovement','Appliances','Kitchen','Music','Video','Blended','HealthPersonalCare','Classical','Software'
]などが有効な値の例です。

これが失敗は成功の母

なぜかAccountがないと怒られる

ちゃんとアソシエイトタグ、アクセスキーID、シークレットキーを設定しているのに何故かAccountがないよ、登録してよと怒られました。

Your [AWSアクセスキーID] is not registered as an Amazon Associate. Please register as an associate at ...

割りと悩んだのですが、どの国のAmazonかを指定していなかったのが原因でした。
なので、国を指定してあげればいいんです。

改善前

Amazon::Ecs.item_search(search_word, {:search_index => 'KindleStore', :response_group => 'ItemAttributes' })

改善後

Amazon::Ecs.item_search(search_word, {:search_index => 'KindleStore', :response_group => 'ItemAttributes', :country => 'jp' })

どの国のAmazonのアカウントかを指定しない場合、でふぉるとで 米国になると思います。
多分、世界でアカウント共有じゃなくてそれぞれの国でアカウントは別々になってるのかな・・・。

Kindle Unlimited本をどう取得するか悩む

Kindle Unlimited本はどういうカテゴリ扱いか、どうすれば取得できるのかをあーだこーだ色々悩みました。
例えば、0円のKindle本を探せば良いのか、それともUnlimitedというカテゴリがあるのか。 バリエーションとしてUnlimitedがあるのか、等色々調べた結果、

下のHPの

このページのノードIDは 4119059051 なので(URLから分かる)
Kindleの最新セール情報を知るためのオフィシャルな方法

で、ピンときてAmazonKindle Unlimitedのトップページを見たら、ノード番号が4486610051とあったのでこれを使えば!と気付き、 f:id:stonebeach-dakar:20161127211748p:plain

ItemSearchのブロック引数にKindleUnlimitedのノード番号を渡すことでOK。

KINDLE_UMLIMITED_BROWSE_NODE_ID = 4486610051
res = Amazon::Ecs.item_search(search_word, {:search_index => 'KindleStore', :browse_node => KINDLE_UMLIMITED_BROWSE_NODE_ID, :response_group => 'ItemAttributes', :country => 'jp'})

f:id:stonebeach-dakar:20161127211910p:plain

ただし、公式ドキュメントでは

ブラウズノードIDは変更・削除される可能性があるため、ハードコーディングは避けてください。

と書かれています。ですが、

高レベルのブラウズノードIDは変更される可能性は低い

とも書かれていましたので比較的高いレベル(本とかKindleとか)なら変わる可能性は低いので埋め込んでも問題無いかもしれません。
こういうときのベストプラクティスはなになのか、ちょっと確認しておきたいところです。

Amazonは様々なカテゴリをこのノードで管理していおり、これらを使うことで検索精度を上げるアーキテクチャになっているそうです。

あとがき

今回で、色々思い知ったのは公式ドキュメントが不親切だと色々苦労するなぁ、ということ。
システムがどんどんアップデートしてAPIは古いままだとちょっと大変だな、と実感。ドキュメント管理は大切だ。
今回使ったGem Amazon-Ecsですが、個人的にちょっと改善したい機能があったので、Gemの公開手順とかの勉強がてら今度改造してみようかと思います。