You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将Selenium Driver传入Scrapy框架?

解决Scrapy中集成Selenium Driver的问题

我太懂这种卡壳的感觉了——第一次尝试把Selenium和Scrapy结合的时候,我对着文档翻了半天也摸不清头绪,更别说套进自己的代码里了!别慌,我给你拆解两种最实用的实现方式,你可以直接照着改你的爬虫。


方法一:直接在爬虫中生成HtmlResponse(快速上手)

这种方法适合小型爬虫或者快速测试,不需要额外配置中间件,直接在start_requests里用Selenium获取页面源码,再生成Scrapy能识别的HtmlResponse对象传给解析函数。

修改后的完整代码如下:

import scrapy
from selenium import webdriver
from time import sleep
from scrapy.http import HtmlResponse

count = 0

class ContractSpider(scrapy.Spider):
    name = "contracts"

    def start_requests(self):
        urls = [
            'https://www.contractsfinder.example.com'  # 替换成你的目标URL
        ]
        
        # 初始化Chrome驱动(换成Firefox等也可以,记得对应安装驱动)
        driver = webdriver.Chrome()
        
        for url in urls:
            driver.get(url)
            # 这里可以加你的Selenium操作:比如点击按钮、输入内容、等待元素加载
            # 建议用WebDriverWait显式等待代替sleep,更可靠,示例:
            # from selenium.webdriver.support.ui import WebDriverWait
            # from selenium.webdriver.support import expected_conditions as EC
            # WebDriverWait(driver, 10).until(EC.presence_of_element_located(('xpath', '//your-element')))
            sleep(2)  # 临时用sleep演示,实际项目替换成显式等待
            
            # 获取当前页面的HTML源码
            page_html = driver.page_source
            # 生成HtmlResponse,传给parse方法
            yield HtmlResponse(
                url=url,
                body=page_html,
                encoding='utf-8',
                request=scrapy.Request(url)
            )
        
        # 爬虫结束后一定要关闭驱动,避免资源泄漏
        driver.quit()

    def parse(self, response):
        global count
        count += 1
        self.log(f'正在处理第 {count} 页: {response.url}')
        # 这里就和普通Scrapy爬虫一样解析了,比如提取标题
        page_title = response.xpath('//title/text()').get()
        if page_title:
            yield {'页面标题': page_title}
        # 有分页的话继续yield Request,同样可以用Selenium处理

关键要点:

  • 必须导入scrapy.http.HtmlResponse,它是Scrapy能识别的响应对象
  • 用完Selenium驱动后记得调用driver.quit(),不然会残留浏览器进程
  • 优先用显式等待(WebDriverWait)代替sleep,能更精准地等待元素加载完成,避免不必要的等待时间

方法二:使用Selenium下载中间件(优雅且可扩展)

如果你的爬虫需要处理大量请求,或者希望代码结构更清晰,推荐用这种方法。中间件会自动拦截所有Scrapy请求,用Selenium处理后再返回响应,爬虫本身不需要写任何Selenium逻辑。

步骤1:编写中间件

在你的Scrapy项目的middlewares.py文件中添加以下代码:

from scrapy import signals
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from scrapy.http import HtmlResponse

class SeleniumMiddleware:
    @classmethod
    def from_crawler(cls, crawler):
        # 从项目配置中读取参数(可选),比如是否启用无头模式
        middleware = cls()
        # 绑定爬虫关闭信号,确保驱动被关闭
        crawler.signals.connect(middleware.spider_closed, signal=signals.spider_closed)
        return middleware

    def __init__(self):
        # 配置Chrome无头模式,适合服务器运行
        chrome_options = webdriver.ChromeOptions()
        chrome_options.add_argument('--headless=new')  # 新版无头模式
        chrome_options.add_argument('--disable-gpu')
        chrome_options.add_argument('--no-sandbox')
        # 初始化驱动,设置页面加载超时
        self.driver = webdriver.Chrome(options=chrome_options)
        self.driver.set_page_load_timeout(30)

    def process_request(self, request, spider):
        # 用Selenium加载请求的URL
        self.driver.get(request.url)
        
        # 自定义等待逻辑:比如等待页面核心元素加载完成(这里以id为content的元素为例)
        try:
            WebDriverWait(self.driver, 10).until(
                EC.presence_of_element_located((By.ID, 'content'))
            )
        except Exception as e:
            spider.log(f"等待元素加载超时: {str(e)}")
        
        # 获取页面HTML源码,生成HtmlResponse返回给Scrapy
        page_html = self.driver.page_source
        return HtmlResponse(
            url=self.driver.current_url,
            body=page_html,
            encoding='utf-8',
            request=request
        )

    def spider_closed(self, spider):
        # 爬虫结束时关闭驱动
        self.driver.quit()

步骤2:启用中间件

打开项目的settings.py,找到DOWNLOADER_MIDDLEWARES配置,添加我们的中间件:

DOWNLOADER_MIDDLEWARES = {
    # 替换成你的项目名.middlewares.SeleniumMiddleware
    'your_project_name.middlewares.SeleniumMiddleware': 543,
    # 默认的HttpDownloadMiddleware优先级是600,我们的中间件优先级要比它高(数字越小优先级越高)
}

步骤3:简化你的爬虫代码

现在爬虫里不需要任何Selenium相关代码了,回归最简洁的Scrapy写法:

import scrapy

count = 0

class ContractSpider(scrapy.Spider):
    name = "contracts"

    def start_requests(self):
        urls = [
            'https://www.contractsfinder.example.com'
        ]
        for url in urls:
            yield scrapy.Request(url=url, callback=self.parse)

    def parse(self, response):
        global count
        count += 1
        self.log(f'正在处理第 {count} 页: {response.url}')
        # 正常写解析逻辑就行,比如提取数据
        page_title = response.xpath('//title/text()').get()
        if page_title:
            yield {'页面标题': page_title}
        # 如果有分页链接,直接yield Request,中间件会自动用Selenium处理

两种方法对比

  • 方法一:快速实现,适合小项目或测试场景,但代码耦合度高,爬虫里混合了Selenium逻辑
  • 方法二:代码结构清晰,可扩展性强,适合大型爬虫,所有Selenium逻辑都集中在中间件里,方便维护和修改

你可以根据自己的项目规模选择合适的方式,要是还有不清楚的地方,随时问!

内容的提问来源于stack exchange,提问作者user3294008

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 11:18:18