瀏覽器調試分析
商品列表url分析
打開京東網站,隨便輸入一個關鍵字,點開抓包工具(ctrl+F)
看到不是動態加載的是不是有點激動?但是你拿到的並不是全數據,為什么這么說呢,往下看
當滑動滾輪時,出現了新數據
查看請求url及參數
嘗試去掉不必要的參數,經過多次的嘗試發現,要獲取到數據只需要想它發送請求就可以拿到數據:
url:https://search.jd.com/s_new.php?keyword=電腦&page=1&s=30
# 注意page與s的關系,注意最大頁碼的值(商品頁面顯示頁碼為100,那么你在拼接url時,最大頁碼必須是100*2) 參數: keyword:搜索的關鍵字 page:頁碼數 s:每一頁的數據條數
但是,你會發現他只能拿到三十幾條左右的數據,而正常是當滾輪滑動到底端時會有六十幾條數據,這時候不要慌,因為你會發現當url的page=2&s=60時,就會出現,原來滾輪滑動到底部后獲取的新數據
因此,當滾輪滑動到底部時,原來的1頁,展示了兩頁的數據。
既然明白了他們的數據請求方式,那么拿到所有的商品列表就很簡單了
拿到后發送請求獲取到response,進行xpath解析就可以了
詳情頁評論分析
上面我們已經獲取了商品列表頁需要的數據,記得拿詳情頁的url
接下來繼續分析詳情頁數據接口的url:隨便點擊一個商品,抓包,全局搜索
查看請求的url:
分析url和參數:
將這里的請求url輸入瀏覽器地址欄,看能否拿到數據:
很明顯,可以拿到數據,接着我們看攜帶的參數
url:https://club.jd.com/comment/productPageComments.action?callback=fetchJSON_comment98&productId=100006581268&score=0&sortType=5&page=0&pageSize=10&isShadowSku=0&fold=1 參數: callback: fetchJSON_comment98 # 這是個回調函數 productId: 100006581268 # 商品id score: 0 # 不知道啥東西 sortType: 5 # 不知道啥東西 page: 0 # 評論的頁碼 pageSize: 10 # 每頁顯示幾條數據 isShadowSku: 0 fold: 1
我們雖然拿到這些參數,但是,你會疑惑這些參數是不是通過js動態生成的?怎么獲取這些參數呢?
其實:對於這種情況來說,先不要老是想着找它的來源,因為有時候就單純的獲取數據來說,有些參數並不是必須要攜帶的
這里,我們嘗試去掉一些不必要的參數
url:https://club.jd.com/comment/productPageComments.action?productId=100003383325&score=0&sortType=5&page=3&pageSize=10 參數: productId:商品id score:不知道啥東西,但這個必須帶 sortType:同上 page:評論的頁碼 pageSize:每頁評論的條數
至此,我們的評論數據接口就搞定了
解決只能爬取70條左右的評論的問題
京東做了反扒機制,當你訪問評率過快或者使用單個ip訪問的時候只允許你拿70左右的數據,如何解決呢?
ip代理池+設置請求發送的間隔時間:以scrapy框架為例:
IP代理池(本人ip代理是從網上爬取的免費代理,存放在數據庫中):
下載器中間件文件:
class AllJdDownloaderMiddleware: # Not all methods need to be defined. If a method is not defined, # scrapy acts as if the downloader middleware does not modify the # passed objects. conn = None cursor = None proxy_list = [] def __init__(self): self.conn = pymysql.Connect(host=MYSQL_IPS_CONNECT['host'], user=MYSQL_IPS_CONNECT['user'], port=MYSQL_IPS_CONNECT['port'], password=MYSQL_IPS_CONNECT['password'], db=MYSQL_IPS_CONNECT['db_name'], charset='utf8') self.cursor = self.conn.cursor() sql = 'select ip,port,http_type from ips' try: self.cursor.execute(sql) # 取數據庫中所有的ip all_ip = self.cursor.fetchall() if not all_ip: raise ValueError('您沒有代理ip了!') for ips in all_ip: ip, port, http_type = ips self.proxy_list.append(f"{http_type.lower()}s://{ip}:{port}") except Exception as e: print(e) @classmethod def from_crawler(cls, crawler): # This method is used by Scrapy to create your spiders. s = cls() crawler.signals.connect(s.spider_opened, signal=signals.spider_opened) return s def process_request(self, request, spider): request.meta['http_proxy'] = random.choice(self.proxy_list) request.cookie = COOKIE return None def process_response(self, request, response, spider): print(response['cookies']) if (spider.comment_url.split('?')[0] in request.url): if not response.text: # 如果評論頁面數量數據取不到,換代理重新請求 request.meta['http_proxy'] = random.choice(self.proxy_list) return request return response def process_exception(self, request, exception, spider): # 捕獲到異常請求,換代理ip,重新發送請求 request.meta['http_proxy'] = random.choice(self.proxy_list) return request def spider_opened(self, spider): spider.logger.info('Spider opened: %s' % spider.name)
設置請求發送間隔時間:
settings.py
DOWNLOAD_DELAY = 2 # 單位秒
然后你就可以開搞了。
本人此次項目獲取的是每個商品的價格、好評、差評、好評度等數據 ,並未爬取評論,但數據接口是相同的,看一下運行結果
總結一下分析的url:
商品列表url: for page in range(1, 200): url = 'https://search.jd.com/s_new.php?keyword=%s&page=%d&s=%d' % ('電腦', page, page * 30) 參數: keyword:搜索關鍵字 page:列表頁碼 s:展示的商品數量 評論列表url: for page in range(0,100) url = 'https://club.jd.com/comment/productPageComments.action?productId=%s&score=0&sortType=5&page=%d&pageSize=%d' % ('100003383325',page,10) 參數: productId=100003383325 # 商品id,其他參數不變 score=0 sortType=5 page=0 # 評論頁碼數, pageSize=10 # 每頁評論條數
完。。。。。。。。。。。。。