Scrapy實戰篇(六)之Scrapy配合Selenium爬取京東信息(上)


在之前的一篇實戰之中,我們已經爬取過京東商城的文胸數據,但是前面的那一篇其實是有一個缺陷的,不知道你看出來沒有,下面就來詳細的說明和解決這個缺陷。

我們在京東搜索頁面輸入關鍵字進行搜索的時候,頁面的返回過程是這樣的,它首先會直接返回一個靜態的頁面,頁面的商品信息大致是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瀏覽器,並且實現了滾動條的下拉,關閉瀏覽器。控制台打印信息如下。

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM