Scrapy-Splash爬蟲實(shí)戰(zhàn)——爬取JS渲染的動(dòng)態(tài)頁面信息【附貨幣基金爬取篩選代碼】

轉(zhuǎn)載自:https://zhuanlan.zhihu.com/p/130867872

本文概要

  • 展示了一個(gè)使用Scrapy爬取網(wǎng)頁信息的例子——爬取天天基金網(wǎng)的貨幣基金
  • 爬取的信息在JS渲染的動(dòng)態(tài)頁面中,使用headless瀏覽器和Splash配合Scrapy解決問題
  • 提供了docker鏡像和Dockerfile挪略,詳述過程Dockerfile每一行的設(shè)置和其中的坑
  • 仔細(xì)閱讀可以了解Scrapy的基本用法踏揣,配合headless瀏覽器爬取一切疑難頁面假勿,在2.0.1版本下很長一段時(shí)間不用去和環(huán)境死磕了岸霹,直接取用docker鏡像吧。

代碼

qqhard/hj_spider?github.com

任務(wù)

由天天基金網(wǎng)的貨基列表頁進(jìn)入詳情頁

image

爬取詳情頁中一系列信息

image

Scrapy一般流程

Scrapy目前的版本是2.0.1贞奋,其官方文檔在https://scrapy.org/

需要python3.5及以上的環(huán)境窒篱,在linux下需要Ubuntu 14.04及以上。

使用pip和conda很容易安裝注益,pip install Scrapy即可碴巾。

Scrapy提供了腳手架,scrapy startproject tutorial 創(chuàng)建項(xiàng)目丑搔,獲得如下的目錄:

tutorial/
    scrapy.cfg            # deploy configuration file

    tutorial/             # project's Python module, you'll import your code from here
        __init__.py

        items.py          # project items definition file

        middlewares.py    # project middlewares file

        pipelines.py      # project pipelines file

        settings.py       # project settings file

        spiders/          # a directory where you'll later put your spiders
            __init__.py

核心邏輯在Spiders目錄下厦瓢,可以增加多個(gè)python文件提揍,每一個(gè)都描述了一段抓取邏輯,Scrapy可以單獨(dú)其中其中一個(gè)爬蟲煮仇,也可以全部啟動(dòng)劳跃。

from scrapy.spiders import Spider
import scrapy
from scrapy_selenium import SeleniumRequest

class HJSpider(Spider):
    name = 'hj_spider'
    start_urls = ['http://fund.eastmoney.com/HBJJ_dwsy.html']

    def parse(self, response):

        if response.url == 'http://fund.eastmoney.com/HBJJ_dwsy.html':
            urls = response.xpath('//*/td[5][@class="jc"]/nobr/a[1]/@href').extract()[0:4]
            for url in urls:
                yield scrapy.Request(url, callback=self.parse)
        else:
            self.parse_detail(response)

    def parse_detail(self, response):
        name = response.xpath('//*[@id="body"]/div[4]/div[9]/div/div/div[1]/div[1]/div/text()').extract()
        nh_shouyi = response.xpath('//*[@id="body"]/div[4]/div[9]/div/div/div[2]/div[1]/div[1]/dl[4]/dd/span/text()').extract()
        start_date = response.xpath('//*[@id="body"]/div[4]/div[9]/div/div/div[2]/div[1]/div[3]/table/tbody/tr[2]/td[1]/text()').extract()
        scale = response.xpath('//*[@id="body"]/div[4]/div[9]/div/div/div[2]/div[1]/div[3]/table/tbody/tr[1]/td[2]/text()').extract()
        ttt = response.xpath('//*[@id="highcharts-24"]/svg/g[5]/g[3]/rect[4]/@height').extract()
        # print (response.url, name, nh_shouyi, start_date, scale, ttt)
        print ('{};;{};;{};;{};;{};;{}'.format(name[0], response.url, nh_shouyi[0], start_date[0], scale[0], ttt[0]))

spider文件的要素:

  • name屬性必須有,且項(xiàng)目內(nèi)唯一浙垫,scrapy crawl spider_name可以單獨(dú)執(zhí)行該爬蟲
  • start_urls定義起始頁面的url的列表刨仑,爬蟲會(huì)由此遞歸運(yùn)行
  • parse函數(shù)用來解析頁面返回,通過yieldRequest對象夹姥,可以遞歸地運(yùn)行下去

該例子中杉武,我們從基金列表頁的URL進(jìn)入,解析得到每只基金的詳情頁面辙售,進(jìn)入后爬取需要的信息轻抱。

從DOM樹上獲取信息,Scrapy提供了xpath和css兩種選擇器旦部,這里我使用了xpath祈搜,配合chrome瀏覽器,非常的輕松士八。

右擊需要獲取的信息容燕,點(diǎn)擊菜單中的選項(xiàng)。

image

然后就能看到頁面源碼對應(yīng)的位置婚度,右擊復(fù)制xpath缰趋,即可得到代碼中的路徑,自己稍作調(diào)整即可達(dá)到要求陕见。

image

使用命令Scrapy shell url 可以在交互的環(huán)境中調(diào)試秘血。

編寫完成后啟動(dòng)爬蟲 scrapy crawl hj_spider

爬取JS渲染信息

在爬取如下圖標(biāo)信息的時(shí)候,雖然在瀏覽器中可以在DOM樹上看到數(shù)據(jù)评甜,但實(shí)際在Scrapy shell中調(diào)試灰粮,發(fā)現(xiàn)數(shù)據(jù)信息是由JS渲染上的,去分析其AJAX請求和構(gòu)造不是輕而易舉的事情忍坷,我決定引入JS渲染引擎粘舟,一勞永逸地解決。

image

大體有兩種方案佩研,在官方文檔的最下邊柑肴,Pre-rendering JavaScriptUsing a headless browser ,前者配合Splash進(jìn)行JS渲染旬薯,后者使用了所謂的無頭(不顯示)瀏覽器晰骑,兩種方法我都做了嘗試。

Using a headless browser

首先評價(jià)一下這個(gè)方案绊序,考慮爬蟲效率的不推薦使用無頭瀏覽器硕舆,相比Splash它破壞了Scrapy的異步并行性秽荞,優(yōu)勢是它是個(gè)完全的瀏覽器,瀏覽器能做到的他都能做到抚官,模擬登陸較Splash簡單扬跋。更多對比:https://www.cnblogs.com/chaojiyingxiong/p/10246244.html

在百分之九十九的情況下,我都推薦使用Splash附魔JS渲染能力凌节,無論是從效率角度還是安裝環(huán)境的簡易程度上钦听。我之所以會(huì)嘗試了這個(gè)方案,是因?yàn)樵谖疑弦淮螌懪老x(2015年前)倍奢,還沒有Splash的方案朴上,我使用了selenium+phantomJS賦能Scrapy,這次也自然地想這么做娱挨。當(dāng)我完成之后余指,看到屏幕上Selenium報(bào)出一個(gè)warning捕犬,說不再支持phantomJS跷坝,請使用headless browser,我自然去搜索headless browser的方案碉碉,忽略了Splash柴钻。但作為一個(gè)可選方案,還是簡要記錄一下垢粮。

在我的mac上贴届,已經(jīng)安裝了chrome,還需要一個(gè)與之版本相應(yīng)的chromedriver蜡吧,其下載地址在https://sites.google.com/a/chromium.org/chromedriver/downloads 毫蚓,解壓到PATH下即可

image

在shell中輸入命令chromedriver 得到如下所示,即為安裝成功

Starting ChromeDriver 80.0.3987.106 (f68069574609230cf9b635cd784cfb1bf81bb53a-refs/branch-heads/3987@{#882}) on port 9515

另外需要安裝selenium 和 scrapy_selenium 昔善,前者用來控制webdriver元潘,后者是scrapy為了配合selenium實(shí)現(xiàn)的一系列組件。

pip install selenium scrapy_selenium

在settings.py總增加如下代碼君仆,其中chromedriver啟動(dòng)參數(shù)--no-sandbox在docker環(huán)境下是必要的翩概,如果沒有該選項(xiàng),由于在docker環(huán)境下是root用戶返咱,會(huì)提示不能再root用戶下啟動(dòng)钥庇。

from shutil import which

SELENIUM_DRIVER_NAME = 'chrome'
SELENIUM_DRIVER_EXECUTABLE_PATH = which('chromedriver')
SELENIUM_DRIVER_ARGUMENTS=['--headless','--no-sandbox','--disable-dev-shm-usage','blink-settings=imagesEnabled=false']

DOWNLOADER_MIDDLEWARES = {
    'scrapy_selenium.SeleniumMiddleware': 800
}

在構(gòu)造請求時(shí)使用scrapy_selenium庫中的SeleniumRequest

from scrapy_selenium import SeleniumRequest
# yield scrapy.Request(url, callback=self.parse)
yield SeleniumRequest(url=url, callback=self.parse, script='window.scrollTo(0, document.body.scrollHeight);')

Pre-rendering JavaScript

需要先安裝Splash,并啟動(dòng)Splash服務(wù)咖摹,這個(gè)可以使用docker评姨,只要網(wǎng)速夠快,沒有任何坑萤晴。

docker run -p 8050:8050 scrapinghub/splash

看到Server listening on http://0.0.0.0:8050即為啟動(dòng)成功

使用pip安裝scrapy_splash参咙,里面有和Scrapy配合的組件

pip install scrapy_splash

在settings.py中做如下配置龄广,其中SPLASH_URL指定了剛剛啟動(dòng)的Splash服務(wù)地址,DOWNLOADER_MIDDLEWARES和SPIDER_MIDDLEWARES替換一系列能與Splash配合的下載器蕴侧。

SPLASH_URL = 'http://localhost:8050'

DOWNLOADER_MIDDLEWARES = {
    'scrapy_splash.SplashCookiesMiddleware': 723,
    'scrapy_splash.SplashMiddleware': 725,
    'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 810,
}

SPIDER_MIDDLEWARES = {
    'scrapy_splash.SplashDeduplicateArgsMiddleware': 100,
}

DUPEFILTER_CLASS = 'scrapy_splash.SplashAwareDupeFilter'

在構(gòu)造請求時(shí)择同,將scrapy.Request替換為 SplashRequest

from scrapy_splash import SplashRequest

yield SplashRequest(url=url, callback=self.parse)
# yield scrapy.Request(url, callback=self.parse)

install in docker

Using a headless browser的方案相對復(fù)雜,在docker中安裝不易净宵,給出Dockerfile

FROM python:3.6-slim-stretch

# Install essential packages
RUN apt-get update -y \
    && apt-get -y install \
        dumb-init gnupg wget ca-certificates apt-transport-https \
        ttf-wqy-zenhei unzip \
    && rm -rf /var/lib/apt/lists/* /var/cache/apt/*

# Install Chrome Headless Browser
RUN wget -q -O - https://dl.google.com/linux/linux_signing_key.pub | apt-key add - \
    && echo "deb https://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google-chrome.list \
    && apt-get update -y \
    && apt-get -y install google-chrome-stable \
    && apt-get -y install build-essential libssl-dev libffi-dev libxml2-dev libxslt-dev \
    && rm /etc/apt/sources.list.d/google-chrome.list \
    && rm -rf /var/lib/apt/lists/* /var/cache/apt/*

# Install chromedriver
ARG CHROME_DRIVER_VERSION=2.35
RUN wget -O tmp/chromedriver_linux64.zip https://chromedriver.storage.googleapis.com/81.0.4044.69/chromedriver_linux64.zip \
    && unzip tmp/chromedriver_linux64.zip -d tmp \
    && rm tmp/chromedriver_linux64.zip \
    && chmod 755 tmp/chromedriver \
    && mv tmp/chromedriver /usr/bin/chromedriver

# Install scrapy & selenium & scrapy-selenium
RUN pip install scrapy selenium scrapy-selenium

CMD [ "/bin/bash" ]

引用

https://blog.csdn.net/zhangpeterx/article/details/83502641

https://sites.google.com/a/chro

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末敲才,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子择葡,更是在濱河造成了極大的恐慌紧武,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件敏储,死亡現(xiàn)場離奇詭異阻星,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)已添,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進(jìn)店門妥箕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人更舞,你說我怎么就攤上這事畦幢。” “怎么了缆蝉?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵宇葱,是天一觀的道長。 經(jīng)常有香客問我刊头,道長黍瞧,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任原杂,我火速辦了婚禮印颤,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘污尉。我一直安慰自己膀哲,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布被碗。 她就那樣靜靜地躺著某宪,像睡著了一般。 火紅的嫁衣襯著肌膚如雪锐朴。 梳的紋絲不亂的頭發(fā)上兴喂,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼衣迷。 笑死畏鼓,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的壶谒。 我是一名探鬼主播云矫,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼汗菜!你這毒婦竟也來了让禀?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤陨界,失蹤者是張志新(化名)和其女友劉穎巡揍,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體菌瘪,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡腮敌,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了俏扩。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片糜工。...
    茶點(diǎn)故事閱讀 38,018評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖动猬,靈堂內(nèi)的尸體忽然破棺而出啤斗,到底是詐尸還是另有隱情表箭,我是刑警寧澤赁咙,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站免钻,受9級特大地震影響彼水,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜极舔,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一凤覆、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧拆魏,春花似錦盯桦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至卖子,卻和暖如春略号,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工玄柠, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留突梦,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓羽利,卻偏偏與公主長得像宫患,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子这弧,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評論 2 345