如何结合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
相关产品推荐
相关产品推荐

