在之前的一篇實戰之中,我們已經爬取過京東商城的文胸數據,但是前面的那一篇其實是有一個缺陷的,不知道你看出來沒有,下面就來詳細的說明和解決這個缺陷。
我們在京東搜索頁面輸入關鍵字進行搜索的時候,頁面的返回過程是這樣的,它首先會直接返回一個靜態的頁面,頁面的商品信息大致是30個,之所以說是大致,因為有幾個可能是廣告商品,之后,當我們鼠標下滑的使用,京東后台使用Ajax技術加載另外的30個商品數據,我們看上去是60個數據,其實這60個數據是分兩次加載出來的,而且只是在你鼠標下滑到一定的位置才會加載那另外的30個數據。
當你點擊頁面最后的第二頁的時候,仔細觀察新的url你會發現它的頁面顯示是第三頁。
下面是初始第一面和點擊第二頁之后的url
# 第一頁的url
https://search.jd.com/Search?keyword=%E6%89%8B%E6%9C%BA&enc=utf-8&qrst=1&rt=1&stop=1&vt=2&wq=%E6%89%8B%E6%9C%BA&cid2=653&cid3=655&page=1&s=1&click=0
# 點擊第二頁的url
https://search.jd.com/Search?keyword=%E6%89%8B%E6%9C%BA&enc=utf-8&qrst=1&rt=1&stop=1&vt=2&wq=%E6%89%8B%E6%9C%BA&cid2=653&cid3=655&page=3&s=59&click=0
page參數一個是1,一個是3。
因此可以得知,京東的第二頁的信息是使用Ajax加載出來的,而不是直接請求url的形式。如果我們想要拿到另外的30個信息,一方面是需要js渲染,另一方面是實現滾動條下拉,觸發Ajax請求。
知道了過程,下面就是着手解決這個問題,由於Scrapy框架只能加載靜態數據,因此我們需要另外的工具來配合Scrapy實現爬取頁面的完整信息。
我們的技術路線是這樣的,使用selenium加Firefox來實現目的。
實現的過程是這樣的,將selenium作為scrapy的下載中間件,執行js腳本實現滾動條的下拉,並且實現js的渲染。
下面就來演示。
spider.py文件
from scrapy import Spider,Request
from selenium import webdriver
class JingdongSpider(Spider):
name = 'jingdong'
def __init__(self):
self.browser = webdriver.Firefox()
self.browser.set_page_load_timeout(30)
def closed(self,spider):
print("spider closed")
self.browser.close()
def start_requests(self):
start_urls = ['https://search.jd.com/Search?keyword=%E6%96%87%E8%83%B8&enc=utf-8&qrst=1&rt=1&stop=1&vt=2&suggest=1.his.0.0&page={}&s=1&click=0'.format(str(i)) for i in range(1,2,2)]
for url in start_urls:
yield Request(url=url, callback=self.parse)
def parse(self, response):
selector = response.xpath('//ul[@class="gl-warp clearfix"]/li')
print(len(selector))
print('---------------------------------------------------')
這里將webdriver定義在spider文件的好處是,不需要每一次請求url都打開和關閉瀏覽器。
其中的closed()方法,是在爬蟲程序結束之后,自動關閉瀏覽器。
由於這里是演示之用,我們就以一個頁面來測試,看一下最后的結果是不是返回60條數據,如果是60條左右就證明我們的selenium起作用了,如果僅僅是30條左右的數據,就證明失敗。
middlewares.py
下面的這個文件是主要邏輯實現
from scrapy.http import HtmlResponse
from selenium.common.exceptions import TimeoutException
import time
class SeleniumMiddleware(object):
def process_request(self, request, spider):
if spider.name == 'jingdong':
try:
spider.browser.get(request.url)
spider.browser.execute_script('window.scrollTo(0, document.body.scrollHeight)')
except TimeoutException as e:
print('超時')
spider.browser.execute_script('window.stop()')
time.sleep(2)
return HtmlResponse(url=spider.browser.current_url, body=spider.browser.page_source,
encoding="utf-8", request=request)
在程序中,我們執行了js腳本,來實現滾動條下拉,觸發Ajax請求,之后我們簡短的等待,來加載Ajax。 在scrapy官方文檔中,對下載中間件有着比較詳細的說明,當某個下載中間件返回的是response對象的時候,之后的下載中間件將不會被繼續執行,而是直接返回response對象。
之后,我們只需要在設置中將當前的下載中間件添加到settings.py文件中,就可以實現了。
運行程序,會發現自動打開了Firefox瀏覽器,並且實現了滾動條的下拉,關閉瀏覽器。控制台打印信息如下。

不妨多試驗幾個頁面,會發現效果也是一樣的。
