在Scrapy中運(yùn)用Selenium和Chrome

本篇結(jié)合Scrapy尉桩、Selenium與Headless Chrome來(lái)爬取需要js渲染的頁(yè)面瞳筏,本節(jié)以爬取京東搜索手機(jī)的頁(yè)面為例卓缰。

頁(yè)面分析

image.png

可以看到對(duì)于手機(jī)這個(gè)選項(xiàng)喇辽,總共有100頁(yè)的結(jié)果掌挚,從動(dòng)態(tài)圖頁(yè)可以看到,每次頁(yè)面加載并不是一次性加載完的菩咨,而是當(dāng)鼠標(biāo)滾輪向下滾動(dòng)到一定距離的時(shí)候吠式,才會(huì)出現(xiàn)新的搜索結(jié)果,這種是通過(guò)js渲染的方式來(lái)實(shí)現(xiàn)的抽米。
我們可以通過(guò)Selenium的execute_script("window.scrollTo(0, document.body.scrollHeight);")來(lái)模擬向下滑動(dòng)到最底的操作特占。

在看頁(yè)面,從圖中我們可以看出云茸,當(dāng)下一頁(yè)跳轉(zhuǎn)到第2頁(yè)的時(shí)候是目,url中的page值為3,在點(diǎn)擊下一頁(yè)跳轉(zhuǎn)到第3頁(yè)是标捺,url中的page為5懊纳,由此可以推斷出,page的變化與對(duì)應(yīng)的展示頁(yè)面對(duì)應(yīng)關(guān)系為亡容,real_page = 2*(page-1)嗤疯,由此,我們可以得到所有頁(yè)面的url地址萍倡。

實(shí)現(xiàn)

只展示關(guān)鍵源碼身弊,其他settings.py等文件不做展示,具體可見我的Github

# search.py
# -*- coding: utf-8 -*-
import scrapy
from selenium import webdriver
import time
class SearchSpider(scrapy.Spider):
    name = 'search'
    search_page_url_pattern = "https://search.jd.com/Search?keyword=%E6%89%8B%E6%9C%BA&page={page}&enc=utf-8"
    start_urls = ['https://search.jd.com/Search?keyword=%E6%89%8B%E6%9C%BA&enc=utf-8']

    def __init__(self):
        chrome_options = webdriver.ChromeOptions()
        chrome_options.add_argument('--headless')
        chrome_options.add_argument('--no-sandbox')
        self.browser = webdriver.Chrome(chrome_options=chrome_options, executable_path='/usr/local/bin/chromedriver')
        super(SearchSpider, self).__init__()
    def closed(self,reason):
        self.browser.close()        # 記得關(guān)閉

    def parse(self, response):
        total_page = response.css('span.p-skip em b::text').extract_first()
        if total_page:
            for i in range(int(total_page)):
                next_page_url = self.search_page_url_pattern.format(page=2*i + 1)
                yield scrapy.Request(next_page_url, callback = self.parse_page)
                time.sleep(1)

    def parse_page(self, response):
        phone_info_list = response.css('div.p-name a')
        for item in book_info_list:
            phone_name = item.css('a::attr(title)').extract_first()
            phone_href = item.css('a::attr(href)').extract_first()

            yield dict(name=phone_name, href=phone_href)

這里在spider中定義了webdriver,這樣的話就可以避免每次都重新打開一個(gè)新的瀏覽器阱佛。
closed()中要關(guān)閉瀏覽器帖汞。
parse()我們先獲取到頁(yè)面的總頁(yè)數(shù),然后在開始根據(jù)規(guī)則生成url凑术,繼續(xù)爬取翩蘸。
parse_page()中我們根據(jù)頁(yè)面規(guī)則爬取要獲取的信息,不再贅述淮逊。

#middlewares.py
from scrapy import signals
from scrapy.http import HtmlResponse

class JdDownloaderMiddleware(object):
    # 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.

    @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):
        # Called for each request that goes through the downloader
        # middleware.

        # Must either:
        # - return None: continue processing this request
        # - or return a Response object
        # - or return a Request object
        # - or raise IgnoreRequest: process_exception() methods of
        #   installed downloader middleware will be called
        spider.browser.get(request.url)
        for i in range(5):
            spider.browser.execute_script("window.scrollTo(0, document.body.scrollHeight);")
        return HtmlResponse(url = spider.browser.current_url, body = spider.browser.page_source, encoding = 'utf8', request = request)

    def process_response(self, request, response, spider):
        # Called with the response returned from the downloader.

        # Must either;
        # - return a Response object
        # - return a Request object
        # - or raise IgnoreRequest
        return response

    def process_exception(self, request, exception, spider):
        # Called when a download handler or a process_request()
        # (from other downloader middleware) raises an exception.

        # Must either:
        # - return None: continue processing this exception
        # - return a Response object: stops process_exception() chain
        # - return a Request object: stops process_exception() chain
        pass

    def spider_opened(self, spider):
        spider.logger.info('Spider opened: %s' % spider.name)

這邊我們利用DownloadMiddleware的特性催首,在process_request()中使用webdriver來(lái)模擬滾動(dòng)獲取整個(gè)頁(yè)面的源碼,在直接返回一個(gè)Response對(duì)象泄鹏,根據(jù)規(guī)則郎任,當(dāng)返回Response對(duì)象,之后的DownloadMiddle將不會(huì)再運(yùn)行备籽,而是直接返回舶治。

運(yùn)行scrapy crawl search -o result.csv --nolog即可獲得爬取結(jié)果。

總結(jié)

本篇講解了selenium與headless chrome和scrapy的聯(lián)合使用车猬,看怎么爬取動(dòng)態(tài)頁(yè)面的信息霉猛,通過(guò)此方法,再也不用怕需要?jiǎng)討B(tài)渲染的頁(yè)面無(wú)法爬取了珠闰。
自此惜浅,解決了動(dòng)態(tài)爬取動(dòng)態(tài)頁(yè)面的問(wèn)題之后,就要解決爬取規(guī)模的問(wèn)題伏嗜,接下來(lái)將會(huì)學(xué)習(xí)如何使用scrapy-redis來(lái)進(jìn)行分布式爬取坛悉。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市承绸,隨后出現(xiàn)的幾起案子吹散,更是在濱河造成了極大的恐慌,老刑警劉巖八酒,帶你破解...
    沈念sama閱讀 222,729評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件空民,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡羞迷,警方通過(guò)查閱死者的電腦和手機(jī)界轩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,226評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)衔瓮,“玉大人浊猾,你說(shuō)我怎么就攤上這事∪劝埃” “怎么了葫慎?”我有些...
    開封第一講書人閱讀 169,461評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵衔彻,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我偷办,道長(zhǎng)艰额,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,135評(píng)論 1 300
  • 正文 為了忘掉前任椒涯,我火速辦了婚禮柄沮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘废岂。我一直安慰自己祖搓,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,130評(píng)論 6 398
  • 文/花漫 我一把揭開白布湖苞。 她就那樣靜靜地躺著拯欧,像睡著了一般。 火紅的嫁衣襯著肌膚如雪财骨。 梳的紋絲不亂的頭發(fā)上哈扮,一...
    開封第一講書人閱讀 52,736評(píng)論 1 312
  • 那天,我揣著相機(jī)與錄音蚓再,去河邊找鬼。 笑死包各,一個(gè)胖子當(dāng)著我的面吹牛摘仅,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播问畅,決...
    沈念sama閱讀 41,179評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼娃属,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了护姆?” 一聲冷哼從身側(cè)響起矾端,我...
    開封第一講書人閱讀 40,124評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎卵皂,沒(méi)想到半個(gè)月后秩铆,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,657評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡灯变,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,723評(píng)論 3 342
  • 正文 我和宋清朗相戀三年殴玛,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片添祸。...
    茶點(diǎn)故事閱讀 40,872評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡滚粟,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出刃泌,到底是詐尸還是另有隱情凡壤,我是刑警寧澤署尤,帶...
    沈念sama閱讀 36,533評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站亚侠,受9級(jí)特大地震影響曹体,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜盖奈,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,213評(píng)論 3 336
  • 文/蒙蒙 一混坞、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧钢坦,春花似錦究孕、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,700評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至禾酱,卻和暖如春微酬,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背颤陶。 一陣腳步聲響...
    開封第一講書人閱讀 33,819評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工颗管, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人滓走。 一個(gè)月前我還...
    沈念sama閱讀 49,304評(píng)論 3 379
  • 正文 我出身青樓垦江,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親搅方。 傳聞我的和親對(duì)象是個(gè)殘疾皇子比吭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,876評(píng)論 2 361