未購入の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