如何组织多个Scrapy Spider并在不同Spider之间传递数据
方案解答
你当前在单Spider内为不同站点编写独立解析方法的实现,在仅需从A站跳转爬取B/C站内容的轻量场景下是可用的,逻辑链路连贯无需额外中间存储,开发成本很低。但确实存在B/C站解析逻辑和A站爬取流程强耦合的问题,无法满足你后续单独爬取B/C站的需求,不是长期维护的最优解。
下面给两种适配你需求的实现方案,可根据自己的使用场景选择:
方案1:抽离公共解析逻辑,兼顾单Spider便捷性和复用性
你可以把B、C站的解析逻辑完全抽成独立的公共函数/模块,和A站的爬取逻辑解耦,不管是A站跳转的请求还是单独爬B/C站的请求都可以直接调用,不需要重复写解析代码:
- 新建
parsers目录,分别存放B站、C站的解析文件
示例parsers/site_b.py代码:
def parse_site_b(response): return { "article_title": response.xpath('//p[contains(@class, "Header_desktopTextElement")]/text()').get(), "article_content": response.xpath('//div[contains(@class, "content")]//text()').getall() # 其他B站字段解析逻辑统一写在这里 }
- 原有A站Spider直接导入解析函数使用:
from parsers.site_b import parse_site_b from parsers.site_c import parse_site_c class QuotesSpider(scrapy.Spider): name = 'Website A Spider' start_urls = ['start_url'] def parse(self, response): important_news = response.xpath('//div[contains(@class, "importantNews")]//div[contains(@class, "items")]/a') for news in important_news: link = news.xpath('./@href').get() title = news.xpath('.//span[contains(@class, "title")]/text()').get() meta = {"source_title": title, "source_link": link} if 'Website B' in link: yield response.follow(link, callback=parse_site_b, meta=meta) elif 'Website C' in link: yield response.follow(link, callback=parse_site_c, meta=meta)
- 后续需要单独爬B站的时候,单独写个B站Spider直接调用相同的解析函数即可,逻辑完全复用。
方案2:完全拆分独立Spider,适合多场景灵活调用
如果你需要三个Spider完全独立,互不依赖,可以通过中间存储传递A站爬取到的链接和元数据:
- 先运行A站Spider,将爬取到的链接、标题等信息存储为JSON/CSV文件,或者存入数据库、Redis等介质
- 编写独立的B站、C站Spider,在
start_requests方法中读取A站输出的链接作为爬取入口,通过meta参数传递A站拿到的元数据:
示例B站独立Spider代码:
import json import scrapy class SiteBSpider(scrapy.Spider): name = "site_b" # 也可以通过命令行参数传入链接文件路径,灵活度更高 def start_requests(self): with open("a_site_output.json", "r", encoding="utf-8") as f: a_items = json.load(f) for item in a_items: if "Website B" not in item["link"]: continue yield scrapy.Request( url=item["link"], callback=self.parse, # 传递A站拿到的元数据 meta={"source_title": item["title"], "source_link": item["link"]} ) def parse(self, response): # 合并元数据和B站解析结果 result = { "source_title": response.meta["source_title"], "source_link": response.meta["source_link"] } # 调用之前抽离的公共解析逻辑,合并到结果中 from parsers.site_b import parse_site_b result.update(parse_site_b(response)) yield result
这种方案的优势是三个Spider完全解耦,后续单独爬B/C站的时候,只需要传入对应站点的链接列表即可,不需要再运行A站的爬取流程,某一个站点的规则变更也只需要修改对应Spider,维护成本更低。如果爬取量比较大,推荐将中间数据存在Redis或者SQLite中,方便做去重和断点续爬。
内容的提问来源于stack exchange,提问作者stanislax
相关产品推荐
相关产品推荐

