scrapy爬蟲遇到js動態渲染問題

一、傳統爬蟲的問題

scrapy爬蟲與傳統爬蟲一樣,都是通過訪問服務器端的網頁,獲取網頁內容,最終都是通過對於網頁內容的分析來獲取數據,這樣的弊端就在於他更適用於靜態網頁的爬取,而面對js渲染的動態網頁就有點力不從心瞭,因為通過js渲染出來的動態網頁的內容與網頁文件內容是不一樣的

1.實際案例

騰訊招聘:https://careers.tencent.com/search.html

在這裡插入圖片描述

這個網站第一眼看過去是非常中規中矩的結構也很鮮明,感覺是很好爬的樣子,但是當你查看他的網頁文件的時候,就會發現:

在這裡插入圖片描述

網頁文件並沒有太多的內容,全部是引用瞭js做的動態渲染,所有數據都在js中間,這就使我們無法對於網頁的結構進行分析來進行爬取數據

那我們如何,獲取到它實際顯示的頁面,然後對頁面內容進行分析呢?

二、scrapy解決動態網頁渲染問題的策略

目前scrapy解決動態網頁渲染問題的主要有以下三種的解決方法:

seleium+chrome

就是傳統的結合瀏覽器進行渲染,優點就在於,瀏覽器能訪問什麼,他就能夠獲取到什麼,缺點也很明顯,因為它需要配合瀏覽器,所以它的速度很慢。

selenium+phantomjs

與上一種的方式一樣,但是不需要開瀏覽器。

scrapy-splash(推薦)

而scrapy-splash與以上兩種方法對比,它更加快速輕量,由於,他是基於twisted和qt開發的輕量瀏覽器引擎,並提供瞭http api,速度更快,最重要的是他能夠與scrapy非常完美的融合。

三、安裝使用scrapy-splash

1.安裝Docker

由於ScrapySplash要在docker裡使用,我們先安裝docker,過程比較復雜痛苦,略

在安裝的過程中有一個非常嚴峻的問題,那就是docker,需要開啟win10 hyper虛擬服務,這與你在電腦上安裝的VM是相沖突的,所以在使用docker,的時候無法使用VM虛擬機,而且每次切換時都需要重啟電腦,目前這個問題暫時無法解決。

2.安裝splash鏡像

docker run -p 8050:8050 scrapinghub/splash

這個過程異常異常的慢,而且必須是國內的鏡像,才能夠下載下來。

所以我配置瞭兩個國內的下載IP,一個網易的,一個阿裡雲的。

{
  "registry-mirrors": [
    "https://registry.docker-cn.com",
    "http://hub-mirror.c.163.com",
    "https://docker.mirrors.ustc.edu.cn"
  ],
  "insecure-registries": [],
  "debug": true,
  "experimental": false
}

下載完成過後,打開瀏覽器訪問:http://localhost:8050/

在這裡插入圖片描述

這就表示已經安裝完成瞭,命令行不能關閉哦

3.安裝scrapy-splash

pip install scrapy-splash

python沒有花裡胡哨的安裝過程。

四、項目實踐

1.項目的創建和配置過程略

2.settings.py的配置

PIDER_MIDDLEWARES = {
   'scrapy_splash.SplashDeduplicateArgsMiddleware': 100,
}
DOWNLOADER_MIDDLEWARES = {
    'scrapy_splash.SplashCookiesMiddleware': 723,
    'scrapy_splash.SplashMiddleware': 725,
    'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 810,  # 不配置查不到信息
}

HTTPCACHE_ENABLED = True
HTTPCACHE_EXPIRATION_SECS = 0
HTTPCACHE_DIR = 'httpcache'

SPLASH_URL = "http://localhost:8050/"  # 自己安裝的docker裡的splash位置
# DUPEFILTER_CLASS = "scrapy_splash.SplashAwareDupeFilter"
HTTPCACHE_STORAGE = 'scrapy_splash.SplashAwareFSCacheStorage'

3.爬蟲的設計

    def start_requests(self):
        splah_args = {
            "lua_source": """
            function main(splash, args)
              assert(splash:go(args.url))
              assert(splash:wait(0.5))
              return {
                html = splash:html(),
                png = splash:png(),
                har = splash:har(),
              }
            end
            """
        }
        headers = {
            'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) '
                          'Chrome/72.0.3626.109 Safari/537.36',
        }
        yield SplashRequest(url=self.start_url, callback=self.parse, args=splah_args,
                            headers=headers)

這裡我們編寫一個初始化的start_requests方法,這個方法是繼承父類的。

註意我們最後的請求方式SplashRequest,我們不再使用Request,而是使用scrapy-splash的請求方式,這裡也體現瞭它與scope框架的完美融合。

至於裡面的參數,就沒有必要介紹瞭,其中要註意兩個參數argscallback

  • args是配置信息可以參照http://localhost:8050/中的
  • callback下一級處理方法的函數名,最後的方法一定要指向self.parse,這是scrapy迭代爬取的靈魂。

4.解析打印數據

    def parse(self, response):
        print(response.text)
        job_boxs = response.xpath('.//div[@class="recruit-list"]')
        for job_box in job_boxs:
            title = job_box.xpath('.//a/h4/text()').get()
            print(title)

這是通過渲染以後的網頁數據

在這裡插入圖片描述

這裡我們直接獲取職位的標題

在這裡插入圖片描述

這就表明scrapy爬蟲應對動態網頁渲染問題已經解決,也就意味著scrapy能夠處理大部分的網頁,並可以應對一些圖形驗證問題

五、總結與思考

之後遇到的問題,當我們獲取到瞭,職位列表過後,當我們需要訪問詳情頁的時候,我們就必須獲取詳情頁的鏈接,但是騰訊非常的聰明,並沒有采用超鏈接的方式進行跳轉,而是通過用戶點擊事件,然後通過js跳轉,這就造成瞭我們無法獲取詳情頁的鏈接。

當我沮喪的時候,我認真的檢查瞭瀏覽器與服務器的數據交換中,其實它的數據也是通過js進行後臺請求得到的,所以通過對大量的數據進行采集,最終找到瞭他的數據接口(賊開心!!!)

在這裡插入圖片描述

這時候我們就要做取舍瞭,我們想要的是所有數據,並不是渲染出來的網頁,與解析網頁內容相比,直接通過它的接口獲取json數據,更加快捷方便,速度更快,所以我們就要做出取舍,在這裡直接獲取接口數據將更好,錯誤率會更低,速度也會更快。

其實大部分的動態網頁的渲染,都存在與數據端進行請求交互數據,當然也存在一些,直接把數據存在js中間,然後再通過js渲染到網頁上,這時候scrapy-splash就可以發揮價值瞭,尤其是在一些驗證碼,圖形驗證方面更加突出。隨著前端技術的不斷發展,前端對數據的控制更加靈活多樣,這也要求爬蟲的邏輯也需要不斷的跟進,也要求使用新的工具,新的技術,在不斷的探索實踐中跟上時代的步伐。

到此這篇關於scrapy爬蟲遇到js動態渲染問題的文章就介紹到這瞭,更多相關scrapy爬蟲js動態渲染內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: