如何使用Scrapy爬取Angular/Vue动态网站?解决会话Cookie丢失问题
我之前也碰到过一模一样的困扰!当用Scrapy结合Selenium处理JS加载的网站时,默认每次启动ChromeDriver都是全新的浏览器会话,之前设置的国家、货币偏好对应的Cookie自然就丢失了。下面分享几个我亲测有效的解决方案:
方案一:复用同一个Selenium浏览器实例
这是最直接的解决办法——不要每次请求都新建driver对象,而是在爬虫启动时初始化一次,所有请求都复用这个实例,这样会话会一直保持,Cookie也不会重置。
举个简单的代码示例:
from scrapy import Spider from selenium import webdriver from selenium.webdriver.common.by import By class MySpider(Spider): name = "my_spider" start_urls = ["https://example.com"] def __init__(self): # 初始化一次driver,整个爬虫过程复用 self.driver = webdriver.Chrome() # 先完成国家/货币选择的初始化操作 self.driver.get(self.start_urls[0]) # 模拟选择操作(示例:找到下拉框并选择目标选项) # country_select = self.driver.find_element(By.ID, "country-select") # country_select.click() # target_option = self.driver.find_element(By.XPATH, "//option[@value='US']") # target_option.click() # 完成操作后,偏好Cookie已存入当前会话 def parse(self, response): # 用同一个driver访问后续页面,Cookie会自动保留 self.driver.get("https://example.com/next-page") # 提取渲染后的HTML rendered_html = self.driver.page_source # 用Scrapy Selector处理渲染后的内容 selector = Selector(text=rendered_html) # ... 你的解析逻辑 def closed(self, reason): # 爬虫关闭时记得销毁driver,避免残留进程 self.driver.quit()
方案二:手动同步Scrapy与Selenium的Cookie
如果因为某些原因必须使用多个driver实例,或者需要Scrapy的请求和Selenium共享Cookie,可以手动同步两边的Cookie:
从Selenium同步到Scrapy
当你用Selenium完成国家/货币设置后,提取当前会话的Cookie,然后在Scrapy的Request中带上这些Cookie:
# 在Selenium操作完成后获取Cookie selenium_cookies = self.driver.get_cookies() # 转换成Scrapy能识别的键值对格式 scrapy_cookies = {cookie['name']: cookie['value'] for cookie in selenium_cookies} # 后续Scrapy请求带上这些Cookie yield scrapy.Request( url="https://example.com/target-page", cookies=scrapy_cookies, callback=self.parse_target )
从Scrapy同步到Selenium
如果Scrapy已经有了会话Cookie,也可以把它们添加到Selenium的driver中:
# 假设scrapy_cookies是Scrapy请求中获取的Cookie字典 for name, value in scrapy_cookies.items(): self.driver.add_cookie({ 'name': name, 'value': value, 'domain': '.example.com', # 注意要设置目标网站的正确域名 'path': '/' })
方案三:自定义Scrapy下载中间件集成Selenium
如果你的爬虫有大量需要JS渲染的请求,推荐写一个自定义的Downloader Middleware,统一处理JS渲染,并且复用同一个driver实例,这样Cookie会自动在整个爬虫会话中保留。
大致的中间件结构:
from scrapy import signals from scrapy.http import HtmlResponse from selenium import webdriver from selenium.webdriver.common.by import By class SeleniumMiddleware: def __init__(self): self.driver = webdriver.Chrome() # 提前完成国家/货币偏好初始化 self.driver.get("https://example.com") # ... 完成偏好设置操作 @classmethod def from_crawler(cls, crawler): middleware = cls() crawler.signals.connect(middleware.spider_closed, signal=signals.spider_closed) return middleware def process_request(self, request, spider): # 只处理标记了需要JS渲染的请求 if request.meta.get('render_js', False): self.driver.get(request.url) # 返回渲染后的HTML作为Response给Scrapy return HtmlResponse( self.driver.current_url, body=self.driver.page_source, encoding='utf-8', request=request ) return None def spider_closed(self, spider): self.driver.quit()
然后在settings.py中启用这个中间件:
DOWNLOADER_MIDDLEWARES = { 'myproject.middlewares.SeleniumMiddleware': 800, }
调试小技巧
- 可以在代码中打印
self.driver.get_cookies(),确认是否包含国家/货币相关的Cookie字段; - 手动在浏览器中完成偏好设置后,查看开发者工具的Cookie面板,记下对应的Cookie名称,方便在代码中验证是否正确保留。
内容的提问来源于stack exchange,提问作者Sreejith Sasidharan
相关产品推荐
相关产品推荐

