首頁 > 軟體

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

2022-05-27 14:02:44

一、傳統爬蟲的問題

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動態渲染內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com