最近の読書体験を振り返ると、9割近くがKindleでの読書です。読みたい本を買っておいて、好きな時に好きな本を読めるのは非常にありがたいです。一方で、そのスタイルだと積読が多くなります。読みたいリストは無数にあって積読が多いのであれば、買うタイミングは安くなった時に買っておくのがベストでしょう。Amazonでは、様々なKindleセールが行われます。しかし、その告知方法は充分ではないので、ユーザ自身がウォッチしておく必要があります。人間がやるのもバカバカしいので、クローラーにやってもらいましょう。
実現方法案
実現する為には、下記の前提・手順を踏みます。
1. いつか読みたい本は、ウィッシュリストに入れておく
2. ウィッシュリストは公開にしていて、認証なしでアクセス可能にしておく
3. クローラーはウィッシュリストを取得して、対象の商品一覧を取得する
4. 対象商品を1件づつ巡回して、Kindleの商品であれば値引率をチェック
5. 一定の値引率だと通知
実装
それでは、順番に実装方法を考えていきましょう。
ウィッシュリストの取得
Amazonにログイン後に、http://www.amazon.co.jp/gp/registry/wishlist/にアクセスしてください。自分の、1つ、もしくは、複数のウィッシュリストがあるはずです。
そこをクリックすると、固有のIDがついたウィッシュリストのURLのページに遷移するはずです。私の場合は、次のURLです。
http://www.amazon.co.jp/gp/registry/wishlist/3G4653SB32HMZ/
ウィッシュリストの公開設定
リストの公開設定は、右上の方の「リストの設定」から行えます。ポップアップから該当のリストを選んで、公開とするだけです。一方で、リストを公開とすることにより、リスクも皆無ではないです。内容を理解した上で、自己責任でお願いします。
対象商品の一覧を取得する
もはやスクレイピングの仕方を忘れつつありますが、こんな感じで取れます。classの値がa-link-normalを取得すると、ページ本体とレビューのURLが取得できます。本体の方は、相対パスなので補完して表示しています。
require 'nokogiri' require 'open-uri' doc = Nokogiri::HTML(open('http://www.amazon.co.jp/gp/registry/wishlist/3G4653SB32HMZ/')) objects = doc.xpath("//a[@class='a-link-normal']") objects.each {|element| url = element[:href] puts "http://www.amazon.co.jp#{url}" if not url.match(/http/) }
さて問題は、リンク先のページの商品がKindleかどうかです。Amazonは商品をASINというコードで管理しています。紙の本は、ASIN=ISBNとなっています。Kindelやその他の商品の場合、Amazonが付番するコードになっています。ISBNかどうかはコードをチェックすれば出来るけど、Kindleか他の商品かはコードからは、読み取れません。(体系あるのであれば、教えてください。)
ということで、効率悪いけど一度アクセスして個々に確認する方法をとります。この方法のメリットとしては、紙の本しか無かったものがKindle化している場合の検知もできます。
詳細ページの取得
詳細ページについては、UserAgentを偽装しておかないと503になります。(いつからだっけ?)本来であれば、API経由で取ることを推奨しますが、今回は省略です。対象ページのカテゴリーは、IDがnav-subnavのdeta-categoryの属性を参照すれば取得できます。
require 'nokogiri' require 'open-uri' UserAgent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36 ' url="http://www.amazon.co.jp/dp/4787710176?_encoding=UTF8&colid=3G4653SB32HMZ&coliid=I168IVRW8TS0E4" url="http://www.amazon.co.jp/ebook/dp/B00VESYKDU/ref=tmm_kin_swatch_0?_encoding=UTF8&coliid=I3I1RV6FI82PJ5&colid=3G4653SB32HMZ&qid=&sr=" doc = Nokogiri::HTML(open(url, 'User-Agent' => UserAgent)) puts doc.xpath("//div[@id='nav-subnav']").attr("data-category")
紙の書籍の場合はbooksで、Kindleの場合はdigital-textとなります。
紙の書籍の場合の処理
紙の書籍の場合は、Kindleのリンクがあるか探してみましょう。あまり良いやり方ではないですが、Kindle版がある場合は全てのフォーマットのうちで一番左に表示されます。ということで、とりあえず一番左のものをとってKindleだったら処理対象とするという方針にします。
ブラウザで見ているものと、JavaScriptが動かないOpen-URIで取得したもので多少差異があるので戸惑うかもしれませんが、下記のような感じで取得できます。
if doc.xpath("//span[@class='a-button a-spacing-mini a-button-toggle format']/span/a/span").first.text == "Kindle版" puts "http://www.amazon.co.jp#{doc.xpath("//span[@class='a-button a-spacing-mini a-button-toggle format']/span/a").first[:href]}" end
※いろいろ面倒臭がってるので、マサカリ飛んできそうですが。
値引き情報の取得
Kindleの値引きは、2種類あります。ポイント還元と純粋な値引きです。今回は、値引きを対象とします。値引き情報は、savingsRowクラスの中に格納されています。あまり綺麗な形で収まっていないので、正規表現等を併用します。
off_info = doc.xpath("//tr[@class='savingsRow']/td[2]").text
通知
任意のしきい値以上の値引率だとメールで送ると言った感じの実装をすればよいです。メールを送るだけであれば、AWSのSESとかがお勧めです。
感想
構造化していなので面倒くさいです。ウィッシュリストだけスクレピングして、後はProduct Advertising APIを使う方が絶対楽です。Rubyでスクレピングするのであれば、Rubyによるクローラー開発技法という本があります。
Rubyによるクローラー開発技法 巡回・解析機能の実装と21の運用例
- 作者: 佐々木拓郎
- 出版社/メーカー: SBクリエイティブ
- 発売日: 2015/03/02
- メディア: Kindle版
- この商品を含むブログ (1件) を見る
See Also:
プログラマになりたい Advent Calendar 2015 - Qiita
プログラマになりたい Advent Calendar 2015 - Adventar
http://qiita.com/advent-calendar/2015/crawler