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

如何结合Selenium与Scrapy实现登录后数据抓取并存储至SQLite3?

解决Selenium与Scrapy整合的登录后数据抓取问题

我看了你的代码,核心问题是Selenium的登录操作和Scrapy Spider完全脱节——你单独运行了Selenium完成登录,但Scrapy的Spider是独立发起HTTP请求的,根本没用到登录后的会话状态,自然无法访问需要权限的页面数据。下面给你两种可行的整合方案,先从最直接的修改开始:

方案一:在Spider的start_requests中集成Selenium

这种方式把登录逻辑直接放到Scrapy Spider里,登录完成后将Selenium加载的页面源码交给Scrapy的解析函数处理,适合单页面或少量页面的抓取场景。

修正后的完整代码

import scrapy
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.action_chains import ActionChains
from scrapy.http import HtmlResponse
from ..items import googleItem

class GoogleSpider(scrapy.Spider):
    name = 'google'
    allowed_domains = ['Real_url']
    # 这里不再用start_urls,改用start_requests自定义起始逻辑

    def start_requests(self):
        # 1. 执行Selenium登录流程
        username = input("请输入用户名: ")
        password = input("请输入密码: ")
        login_url = "Start_url"

        driver = webdriver.Chrome()
        driver.get(login_url)
        driver.maximize_window()

        # 登录操作
        driver.find_element(By.NAME, "username").send_keys(username)
        driver.find_element(By.NAME, "password").send_keys(password)
        driver.find_element(By.NAME, "wp-submit").send_keys(Keys.ENTER)

        # 确认服务条款(修正xpath的语法错误)
        WebDriverWait(driver, 20).until(
            EC.element_to_be_clickable((By.XPATH, '//input[@type="image" and @src="SiteCommon2006/en/Bluef"]'))
        ).click()

        # 等待并点击高级按钮
        WebDriverWait(driver, 10).until(
            EC.element_to_be_clickable((By.ID, "ContentContainer1_ctl00_Content"))
        ).click()

        # 悬停并点击"所有交易"(修正xpath的闭合引号问题)
        element_to_hover_over = WebDriverWait(driver, 10).until(
            EC.presence_of_element_located((By.XPATH, '//*[@id="ContentContainer1_Content__SearchSearchMenu"]/li[13]'))
        )
        hover = ActionChains(driver).move_to_element(element_to_hover_over)
        hover.perform()

        all_deals_button = WebDriverWait(driver, 10).until(
            EC.element_to_be_clickable((By.XPATH, '//*[@id="ContentContainer1_ctl00_Content"]'))
        )
        all_deals_button.click()

        # 进入交易详情页
        WebDriverWait(driver, 10).until(
            EC.element_to_be_clickable((By.XPATH, '//*[@id="ContentContainer1_ctl00"]/tbody/tr[2]/td[9]/a'))
        ).click()

        # 2. 将Selenium当前页面的源码交给Scrapy解析
        current_url = driver.current_url
        page_source = driver.page_source
        yield HtmlResponse(url=current_url, body=page_source, encoding='utf-8', request=self.make_requests_from_url(current_url))

        # 关闭浏览器(如果后续还有请求可以保留,这里根据需求调整)
        driver.quit()

    def parse(self, response):
        all_div_deal = response.css("div.deal")
        for deal in all_div_deal:
            # 初始化Item实例(原代码缺失这一步)
            item = googleItem()
            item['companies'] = deal.xpath(".//span[@class='text']/text()").get()  # 修正xpath语法,用get()获取单个值
            item['price'] = deal.xpath(".//*[@class='price']/text()").get()
            item['deal_nr'] = deal.xpath(".//*[@class='deal_nr']/text()").get()
            yield item

关键修改点说明

  • 把Selenium登录逻辑移到start_requests方法中,确保Scrapy能拿到登录后的页面
  • 修正了原代码中xpath语法错误(比如缺失闭合引号、路径不完整)
  • 用WebDriverWait替代time.sleep,提升稳定性
  • 初始化googleItem实例,正确赋值字段
  • 通过HtmlResponse将Selenium加载的页面传递给Scrapy的parse方法

方案二:使用Scrapy下载中间件(Downloader Middleware)集成Selenium

如果需要抓取多个页面,且每个页面都需要保持登录状态,推荐用这种方式——让Scrapy的所有请求都通过Selenium驱动的浏览器执行,自动继承登录会话。

步骤1:编写Selenium中间件

在项目的middlewares.py中添加以下代码:

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.action_chains import ActionChains
from scrapy.http import HtmlResponse
import time

class SeleniumMiddleware:
    def __init__(self):
        self.driver = webdriver.Chrome()
        # 提前完成登录流程
        username = input("请输入用户名: ")
        password = input("请输入密码: ")
        login_url = "Start_url"
        self.driver.get(login_url)
        self.driver.maximize_window()

        # 登录操作
        self.driver.find_element(By.NAME, "username").send_keys(username)
        self.driver.find_element(By.NAME, "password").send_keys(password)
        self.driver.find_element(By.NAME, "wp-submit").send_keys(Keys.ENTER)

        # 确认服务条款
        WebDriverWait(self.driver, 20).until(
            EC.element_to_be_clickable((By.XPATH, '//input[@type="image" and @src="SiteCommon2006/en/Bluef"]'))
        ).click()

    def process_request(self, request, spider):
        # 用Selenium加载请求的URL
        self.driver.get(request.url)
        # 这里可以添加页面等待逻辑(比如等待元素加载)
        time.sleep(2)
        # 返回HtmlResponse给Scrapy解析
        return HtmlResponse(url=self.driver.current_url, body=self.driver.page_source, encoding='utf-8', request=request)

    def spider_closed(self, spider):
        # 爬虫结束后关闭浏览器
        self.driver.quit()

步骤2:在settings.py中启用中间件

找到DOWNLOADER_MIDDLEWARES配置,添加自定义中间件:

DOWNLOADER_MIDDLEWARES = {
    'your_project_name.middlewares.SeleniumMiddleware': 543,
    # 注释掉默认的HttpCompressionMiddleware,避免冲突
    # 'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 810,
}

步骤3:简化Spider代码

此时Spider只需要定义目标URL和解析逻辑即可:

import scrapy
from ..items import googleItem

class GoogleSpider(scrapy.Spider):
    name = 'google'
    allowed_domains = ['Real_url']
    # 这里填登录后需要抓取的页面URL
    start_urls = ['your_target_page_url']

    def parse(self, response):
        all_div_deal = response.css("div.deal")
        for deal in all_div_deal:
            item = googleItem()
            item['companies'] = deal.xpath(".//span[@class='text']/text()").get()
            item['price'] = deal.xpath(".//*[@class='price']/text()").get()
            item['deal_nr'] = deal.xpath(".//*[@class='deal_nr']/text()").get()
            yield item

注意事项

  • 优先使用WebDriverWait等待元素,避免time.sleep导致的不稳定
  • 确保你的googleItem类在items.py中正确定义了companies、price、deal_nr字段
  • 由于你已经知道如何将数据存储到SQLite,只需要确保Scrapy的Item Pipeline配置正确即可(比如使用scrapy.exporters.SqliteItemExporter或自定义Pipeline)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 11:47:53