chakokuのブログ(rev4)

テック・コミック・ごくまれにチャリ

Amazonのコミック無料ページをクローリングしてASINを収集するソフトを試作

例のKindle無料検索サイトを作成していて、APIで取ってこれる情報は一条件につき10ページまでとなっている。だから、、商品番号(ASIN)は最大100件までしか収集できない(もちろん検索条件を変えればいいのだけど、、無料Kindleコミックの情報をAPIで取得するのに、他に使える条件があるのか分からず)。
そこで、、クローリングの勉強を兼ねて、利用者と同じ無料ページをクローラがクローリングするソフトをPythonで試作した。
Kindleコミックを安いもの順で表示した場合、以下のURL(下記の例は安いもの順、3ページ目を表示した場合の例)

https://www.amazon.co.jp/s/ref=sr_pg_3?rh=n%3A2250738051%2Cn%3A%212250739051%2Cn%3A2275256051%2Cn%3A2293143051&page=3&sort=price-asc-rank&ie=UTF8&qid=1493695869&lo=digital-text

ページが変わると、page=NNNの部分が変わる。逆に言うと、page=NNN(とsr_pg_NN)を指定すれば好きなページに移ることができる。そんな特性を利用してクローラを作ってみた。HTMLを本気でパースするのは大変だけど、商品番号(ASIN)の入っている文字列はパターンが限られるので、パターンに合致するように正規表現で引っこ抜く。
ポイントとしては、、普通にurllib2でアクセスしていると、cookieを食わないおまえはロボットか?とAmazonサイトから応答されるので、cookieを有効にしている。もっと正しい実装もあると思うけど、現状はこれで動いています。ご参考にどうぞ。

#!/usr/bin/python
#
# crawling Amazon Kindle Page and get ASIN Code
#

import sys
import time
import re
import urllib2
import cookielib

URL_TMPL="https://www.amazon.co.jp/s/ref=sr_pg_{:d}?rh=n%3A2250738051%2Cn%3A%212250739051%2Cn%3A2275256051%2Cn%3A2293143051&page={:d}&sort=price-asc-rank&ie=UTF8&qid=1493625872&lo=digital-text"

UERAGENT = 'Mozilla/5.0'
SUSPICIOUS_ROBOT = 'automated access to Amazon data'

#MAXCRAWLINGPAGE = 1  # crawling max page
MAXCRAWLINGPAGE = 35  # crawling max page


cj = cookielib.CookieJar()
cjhdr = urllib2.HTTPCookieProcessor(cj)
opener = urllib2.build_opener(cjhdr)
opener.addheaders = [('User-Agent', UERAGENT)]

asinList = []

for pageNo in range(1, MAXCRAWLINGPAGE + 1):

    print "crawling {:d}th Page\n".format(pageNo)
    print "zzzzz....\n"
    time.sleep(3)
    waitTimeInRetry = 0

    for trial in range(10):
      responseCode=None
      time.sleep(waitTimeInRetry)
      try:
         url = URL_TMPL.format(pageNo, pageNo)
         print "access" + url
         fp = opener.open(url)
         html = fp.read()
         responseCode = fp.getcode()
         fp.close()

         if SUSPICIOUS_ROBOT in html:
              print 'Warning!! access is recognized as ROBOT'
              print "retry"
              waitTimeInRetry = 3
         else:
              break

      except urllib2.URLError as e:
         print "raised Exception"
         print "urllib2.URLError"
         print 'failed to reach a server.'
         print 'Reason: ', e.reason
         print "retry"
         waitTimeInRetry = 3

      except urllib2.HTTPError as e:
         print "raised Exception"
         print "urllib2.HTTPError"
         print "The server couldn't response the request."
         print 'Error code: ', e.code
         print "retry"
         waitTimeInRetry = 3

      except:
         print "raised Exception"
         print("Unexpected error:", sys.exc_info()[0])
         print "retry"
         waitTimeInRetry = 3

    if responseCode != 200:
        print "access failed"
        sys.exit()

    else:
        print "OK[{:d}]".format(responseCode)

    #
    # save crawling taget page for debug
    #
    file = 'crawling_{:d}.html'.format(pageNo)
    f = open(file, 'w')
    f.write(html)
    f.close()

    #
    # pickup ASIN (kindle free contents)
    #
    # find href="xxxxxxx"
    itemList = re.findall('href="([^\"]*)"', html)
    for url in itemList:
       if 'ebook' in url:
           print "-------------------------------\n"
           print url
           print "-------------------------------\n"

           matchAsin  = re.match('.*ebook/dp/([A-Z0-9]*)', url)
           if matchAsin:
               print "find ASIN\n"
               asin = matchAsin.groups()[0]
               if not asin in asinList:   # add to ASIN_LIST only if new one
                   asinList.append(asin)
           else:
               print "Error!! not found\n"

for asin in asinList:
   print asin

f = open('crawl_out.txt', 'w')
for asin in asinList:
   output = "{:s}\n".format(asin)
   f.write(output)
f.close()

■ご参考
(今回は参考にしていませんが、まっとうにクローリングを実装しようとしたらいろいろ考慮必要ということで)
https://blog.hartleybrody.com/scrape-amazon/
Hartley Brody氏
How to Scrape Amazon.com: 19 Lessons I Learned While Crawling 1MM+ Product Listings

■補足
Amazonサイトではクローリングを禁止しているとのとで、このようなプログラムによるWebサイトアクセスは使用許諾違反になるようです。あまり悪質だとIP制限がかかるらしい。ですので、、もしそういう行為をされる場合はご注意ください。
「プログラムによるアクセスはAPIを使うこと」というのが正しい答えです。ただ、、APIでも取れない情報があるのでそれは困った点です。(Kindle版コンテンツの価格、レビューアによるコメント(星いくつ)といった情報はAPIでは取れない)