未購入のKindle無料コミック探しを時間短縮したい
無料本は何冊購入したとしても、0円×∞=0円です。お財布が痛まないため、読む読まないに関係なくとりあえずポチッとするようにしています。しかしながら、Amazonの商品検索をすると購入済みと未購入のものが混ざって表示されますので、1000冊以上ある無料本を全部見て、そのなかから未購入のもののみをポチッとするのは時間のムダだなとずっと思っていました。スクリプトを書いて、自動化するところまでできたっぽいので記事を書きます。
Rubyでスクリプトを書くとこうなる。
以下のコードで、"ASIN", "本のページへのリンク", "サムネイル画像", "タイトル"が取得できます。Nokogiriをつかうのに、10年以上ぶりにXPathをつかいました。便利ですねこれ。
require 'open-uri' require 'nokogiri' def find_items(url) items = [] opt = {} charset = nil html = open(url, opt) do |f| charset = f.charset f.read end doc = Nokogiri::HTML.parse(html, nil, charset) result = doc.xpath('//li[contains(@id, "result_")]') unless result.length == 0 result.each do |r| a = r.xpath('descendant::a[@class="a-link-normal s-access-detail-page s-color-twister-title-link a-text-normal"]') img = r.xpath('descendant::img') items.push([r.attribute('data-asin').value, a.attribute('href').value, img.attribute('src').value, a.inner_text]) end end return items end def find_free_comics(page) STDERR.puts page.to_s url = 'https://www.amazon.co.jp/%E3%82%B3%E3%83%9F%E3%83%83%E3%82%AF-0-Kindle%E6%9C%AC/s?ie=UTF8&rh=n%3A2293143051%2Cp_36%3A-0&page='+page.to_s return find_items(url) end find_free_comics(1).each do |c| puts c.join(",") end
こちらのサンプルコードでは無料のKindleコミックを取得していますが、URLを変えれば無料本ではなくても同じことができます。
あとはこれをページの数だけ繰り返し、さらに保存しておいた過去の検索結果と照らして、もし新しいASINの本があれば、それを表示すればよいです。ただし、Amazonは利用規約において、製品リストの取得を許可していませんので、ここから先は自己責任になると存じます。
ちなみに、Amazon Product APIではうまくいかない。
当初はAmazon Product APIで同じことを試したのですが、うまくいかないようです。 APIのひとつであるItemSearchは、一度に10件までしか出力できません。item_pageを1〜10の間で指定することで、最大100件までは取得できますが、それでもたかだか100件しか取得できないのは厳しいです。無料コミックは1000冊以上あります。またAPIを何度も連続で叩くと、Amazonからエラー応答が返ってくるので、一覧の取得は困難です。
ItemSearch - Product Advertising API
あくまで参考としてですが、以下のコードは、キーさえ書き換えれば100件まで取得できます。次のサイトのコードをほぼそのままコピーしていますが、1箇所だけ修正しており、marketplaceではなくcountryにするとよいです。
atton.blog: amazon-ecs を使って Kindle マンガの情報を取得する #okinawarb
なお2293143051はAmazonのブラウズノードであり、次のページのURIのものを利用しています。この値を用いると、Kindleのコミックスすべてから検索することになります。
Kindleマンガストア コミック | Amazon | アマゾン
require 'amazon/ecs' Amazon::Ecs.configure do |options| options[:associate_tag] = 'xxx' options[:AWS_access_key_id] = 'xxx' options[:AWS_secret_key] = 'xxx' end page = 1 loop do res = Amazon::Ecs.send_request({response_group: 'Medium', operation: 'ItemSearch', search_index: 'Books', browse_node: '2293143051', minimum_price: 0, maximum_price: 0, item_page: page, country: 'jp'}) res.items.each do |item| puts item end if page >= res.total_pages break else STDERR.puts page.to_s + "/" + ((res.total_results-1)/10 +1).to_s page += 1 sleep 2 end end