1. 程式人生 > >小白學 Python 爬蟲(41):爬蟲框架 Scrapy 入門基礎(八)對接 Splash 實戰

小白學 Python 爬蟲(41):爬蟲框架 Scrapy 入門基礎(八)對接 Splash 實戰

人生苦短,我用 Python

前文傳送門:

小白學 Python 爬蟲(1):開篇

小白學 Python 爬蟲(2):前置準備(一)基本類庫的安裝

小白學 Python 爬蟲(3):前置準備(二)Linux基礎入門

小白學 Python 爬蟲(4):前置準備(三)Docker基礎入門

小白學 Python 爬蟲(5):前置準備(四)資料庫基礎

小白學 Python 爬蟲(6):前置準備(五)爬蟲框架的安裝

小白學 Python 爬蟲(7):HTTP 基礎

小白學 Python 爬蟲(8):網頁基礎

小白學 Python 爬蟲(9):爬蟲基礎

小白學 Python 爬蟲(10):Session 和 Cookies

小白學 Python 爬蟲(11):urllib 基礎使用(一)

小白學 Python 爬蟲(12):urllib 基礎使用(二)

小白學 Python 爬蟲(13):urllib 基礎使用(三)

小白學 Python 爬蟲(14):urllib 基礎使用(四)

小白學 Python 爬蟲(15):urllib 基礎使用(五)

小白學 Python 爬蟲(16):urllib 實戰之爬取妹子圖

小白學 Python 爬蟲(17):Requests 基礎使用

小白學 Python 爬蟲(18):Requests 進階操作

小白學 Python 爬蟲(19):Xpath 基操

小白學 Python 爬蟲(20):Xpath 進階

小白學 Python 爬蟲(21):解析庫 Beautiful Soup(上)

小白學 Python 爬蟲(22):解析庫 Beautiful Soup(下)

小白學 Python 爬蟲(23):解析庫 pyquery 入門

小白學 Python 爬蟲(24):2019 豆瓣電影排行

小白學 Python 爬蟲(25):爬取股票資訊

小白學 Python 爬蟲(26):為啥買不起上海二手房你都買不起

小白學 Python 爬蟲(27):自動化測試框架 Selenium 從入門到放棄(上)

小白學 Python 爬蟲(28):自動化測試框架 Selenium 從入門到放棄(下)

小白學 Python 爬蟲(29):Selenium 獲取某大型電商網站商品資訊

小白學 Python 爬蟲(30):代理基礎

小白學 Python 爬蟲(31):自己構建一個簡單的代理池

小白學 Python 爬蟲(32):非同步請求庫 AIOHTTP 基礎入門

小白學 Python 爬蟲(33):爬蟲框架 Scrapy 入門基礎(一)

小白學 Python 爬蟲(34):爬蟲框架 Scrapy 入門基礎(二)

小白學 Python 爬蟲(35):爬蟲框架 Scrapy 入門基礎(三) Selector 選擇器

小白學 Python 爬蟲(36):爬蟲框架 Scrapy 入門基礎(四) Downloader Middleware

小白學 Python 爬蟲(37):爬蟲框架 Scrapy 入門基礎(五) Spider Middleware

小白學 Python 爬蟲(38):爬蟲框架 Scrapy 入門基礎(六) Item Pipeline

小白學 Python 爬蟲(39): JavaScript 渲染服務 Scrapy-Splash 入門

小白學 Python 爬蟲(40):爬蟲框架 Scrapy 入門基礎(七)對接 Selenium 實戰

引言

前面我們介紹了使用 Scrapy 對接 Selenium 來抓取由 JavaScript 動態渲染的網頁,那麼除了這種方式,是否還有其他的解決方案?

答案當然是肯定的,前面我們同樣介紹了 Splash 這個 JavaScript 動態渲染服務,本篇文章,我們就來介紹如何使用 Scrapy 對接 Splash 抓取由 JavaScript 動態渲染的網頁。

示例

準備

首先需確保已經正確安裝 Splash 服務,同時包括 Scrapy-Splash 庫,還沒有安裝的同學,可以參考前面的文章 「小白學 Python 爬蟲(39): JavaScript 渲染服務 Scrapy-Splash 入門」 進行安裝。

新建專案

本篇內容還是新建一個新的 Scrapy 專案,並且命名為 scrapy_splash_demo ,命令如下:

scrapy startproject scrapy_splash_demo

記得找一個自己喜歡的目錄,最好是純英文目錄。

然後新建一個 Spider ,命令如下:

scrapy genspider jd www.jd.com

本篇的示例嘛還是使用之前 Splash 的示例,畢竟本文的內容主要是介紹 Scrapy 如何對接 Splash ,當然另一個更主要的原因是小編也比較懶嘛~~~

配置

這裡的配置可以參考官方的 Github 倉庫,連結:https://github.com/scrapy-plugins/scrapy-splash 。

首先先在 settings.py 中新增 Splash 服務的地址,因為小編這裡使用的是本地的服務,所以直接就配置了本地的連結。

SPLASH_URL = 'http://localhost:8050/'

如果 Splash 服務是在遠端的伺服器上執行的,那麼這裡就應該配置遠端伺服器的地址,如 Splash 服務是執行在遠端的 172.16.15.177 上的,那麼需要的配置就是:

SPLASH_URL = 'http://172.16.15.177:8050/'

接下里需要配置幾個 DOWNLOADER_MIDDLEWARES ,如下:

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

我們還需要配置一個 SPIDER_MIDDLEWARES ,如下:

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

接下來,需要配置一個去重的 Python 類 SplashAwareDupeFilter ,如下:

DUPEFILTER_CLASS = 'scrapy_splash.SplashAwareDupeFilter'

我們還需要配置一個 Cache 儲存的 SplashAwareFSCacheStorage ,如下:

HTTPCACHE_STORAGE = 'scrapy_splash.SplashAwareFSCacheStorage'

接下來,我們就可以開始搞事情了。

傳送請求

上面我們已經將該配置的都配置完成了,這裡我們可以直接使用 SplashRequest 物件並傳遞相應的引數, Scrapy 會將此請求轉發給 Splash ,Splash 將頁面載入渲染,渲染完成後再將結果傳遞回來,這時的 Response 就是經過 Splash 渲染的結果了,這裡直接交給 Spider 解析就好了。

我們先來看下官方的示例,如下:

yield SplashRequest(url, self.parse_result,
    args={
        # optional; parameters passed to Splash HTTP API
        'wait': 0.5,

        # 'url' is prefilled from request url
        # 'http_method' is set to 'POST' for POST requests
        # 'body' is set to request body for POST requests
    },
    endpoint='render.json', # optional; default is render.html
    splash_url='<url>',     # optional; overrides SPLASH_URL
    slot_policy=scrapy_splash.SlotPolicy.PER_DOMAIN,  # optional
)

這裡直接構造了一個 SplashRequest 物件,前兩個引數是目標 URL 以及回撥的方法,另外我們可以通過 args 傳遞一些引數,如等待的時間,這個示例中是 0.5 。

更多的說明還是參考官方 Github 倉庫,地址:https://github.com/scrapy-plugins/scrapy-splash 。

或者我們也可以使用 scrapy.Request , Splash 相關的配置通過 meta 配置就好了,接著看一個官方的示例,如下:

yield scrapy.Request(url, self.parse_result, meta={
    'splash': {
        'args': {
            # set rendering arguments here
            'html': 1,
            'png': 1,

            # 'url' is prefilled from request url
            # 'http_method' is set to 'POST' for POST requests
            # 'body' is set to request body for POST requests
        },

        # optional parameters
        'endpoint': 'render.json',  # optional; default is render.json
        'splash_url': '<url>',      # optional; overrides SPLASH_URL
        'slot_policy': scrapy_splash.SlotPolicy.PER_DOMAIN,
        'splash_headers': {},       # optional; a dict with headers sent to Splash
        'dont_process_response': True, # optional, default is False
        'dont_send_headers': True,  # optional, default is False
        'magic_response': False,    # optional, default is True
    }
})

這兩種傳送 Request 請求的方式是相同的,選哪個都可以。

本篇文章中使用的 Lua 指令碼還是之前文章中的指令碼,具體 Lua 指令碼內容如下:

function main(splash, args)
  splash:go("https://www.jd.com/")
    return {
      url = splash:url(),
      jpeg = splash:jpeg(),
      har = splash:har(),
      cookies = splash:get_cookies()
    }
end

結果如下:

接下來,我們在 Spider 中使用 SplashRequest 對接 Lua 指令碼就好了,事情就是這麼簡單,如下:

# -*- coding: utf-8 -*-
import scrapy
from scrapy_splash import SplashRequest


lua_script = """
function main(splash, args)
  splash:go(args.url)
    return {
      url = splash:url(),
      jpeg = splash:jpeg(),
      har = splash:har(),
      cookies = splash:get_cookies()
    }
end
"""


class JdSpider(scrapy.Spider):
    name = 'jd'
    allowed_domains = ['www.jd.com']
    start_urls = ['http://www.jd.com/']

    def start_requests(self):
        url = 'https://www.jd.com/'
        yield SplashRequest(url=url, callback=self.parse)

    def parse(self, response):
        self.logger.debug(response.text)

Spider 寫好了以後可以使用命令執行這個爬蟲了,命令如下:

scrapy crawl jd

具體的結果小編這裡就不貼了,只是簡單的將響應回來的資料已日誌的形式打印出來了,不過如果仔細觀察打出來的資料,可以看到原來由 JavaScript 動態渲染的部分也打印出來了,說明我們的 Scrapy 對接 Splash 實戰成功。

示例程式碼

本系列的所有程式碼小編都會放在程式碼管理倉庫 Github 和 Gitee 上,方便大家取用。

示例程式碼-Github

示例程式碼-Gi