iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

0

Day 21 的內容中有介紹 Seleniumpuppeteer 兩種在程式中操作瀏覽器的方式,今天來看看怎麼在 Scrapy 中使用。

Selenium

因為在 Spider 類別中只需要關注剖析的邏輯,不應該在這邊決定是否使用 Selenium,所以會建立一個 Downloader Middlewares 元件來處理。這個元件應該要做幾件事:

  1. 元件初始化時載入 WebDriver
from scrapy import signals
from selenium import webdriver

class SeleniumMiddleware:
    def __init__(self):
        self.driver = webdriver.Chrome('./chromedriver.exe')

    @classmethod
    def from_crawler(cls, crawler):
        middleware = cls()

        crawler.signals.connect(middleware.spider_closed, signals.spider_closed)

        return middleware

    def spider_closed(self):
        self.driver.quit()
  1. 處理請求時決定是否要使用 Selenium
from scrapy.http import HtmlResponse

class SeleniumMiddleware:
    def process_request(self, request, spider):
        '''
        不是每個請求都需要用 Selenium,
        另外包裝一個 Request 類別,
        如果 spider 回傳的是此類別的實體,
        才使用 Selenium 來發請求
        '''
        if not isinstance(request, SeleniumRequest):
            # 回傳 None 會繼續執行下一個元件
            return None

        self.driver.get(request.url)

        body = str.encode(self.driver.page_source)

        return HtmlResponse(
            self.driver.current_url,
            body=body,
            encoding='utf-8',
            request=request
        )

from scrapy import Request

class SeleniumRequest(Request):
    '''
    另外包裝的 Request 類別,用來判斷是否要使用 Selenium
    '''
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

建立好元件後,要記得將元件加入 Downloader Middlewares 的執行序列中

DOWNLOADER_MIDDLEWARES = {
   'ithome_crawlers.middlewares.SeleniumMiddleware': 800
}

最後在 Spider 中要回傳對應的 Request 實體,才會用 Selenium 來處理

class IthomeSpider(scrapy.Spider):
    name = 'ithome'
    allowed_domains = ['ithome.com.tw']
    
    def start_requests(self):
        for page in range(1, 2):
            yield SeleniumRequest(url=f'https://ithelp.ithome.com.tw/articles?tab=tech&page={page}', callback=self.parse)

不要自己造輪子

已經有大大寫好完整的套件可以使用了:clemfromspace/scrapy-selenium。上面的說明是參考這個套件的原始碼來說明建立元件時的流程邏輯。

  1. 安裝套件
pipenv install scrapy-selenium
  1. settings.py 中設定相關參數
SELENIUM_DRIVER_NAME = 'chrome'
SELENIUM_DRIVER_EXECUTABLE_PATH = './chromedriver.exe'
SELENIUM_DRIVER_ARGUMENTS = ['-headless']  # 用 Headless Chrome 模式啟動
  1. 把元件加入執行序列
DOWNLOADER_MIDDLEWARES = {
    'scrapy_selenium.SeleniumMiddleware': 800
}
  1. 回傳對應的 Request 實體
from scrapy_selenium import SeleniumRequest

yield SeleniumRequest(url=url, callback=self.parse)

puppeteer

同一位大大也有做了使用 puppeteer 的套件:clemfromspace/scrapy-puppeteer,但很久沒更新了,用起來也有問題,這邊就不花時間介紹啦。

參考資料


上一篇
【Day 30】在程式中啟動 Scrapy 爬蟲
下一篇
【Day 32】Scrapy 爬取 iT 邦幫忙的回文
系列文
爬蟲在手、資料我有 - 30 天 Scrapy 爬蟲實戰33

尚未有邦友留言

立即登入留言