如何在单个Python脚本中调用两个Scrapy爬虫并解决代码重复问题?
方案1:单CrawlSpider整合全量+重爬逻辑
如果重爬逻辑和常规爬取差异不大,优先选该方案,只需维护一套代码,无需分开配置触发任务:
- 利用Scrapy的
spider_idle信号,在常规爬取任务全部跑完、爬虫进入空闲状态时,自动拉取数据库中缺失的URL加入爬取队列 - 完全复用原有
parse_item解析逻辑,无重复代码 - 重爬请求可单独配置更高重试次数、自定义代理头等参数
示例代码:
import scrapy from scrapy import signals from scrapy.spiders import CrawlSpider from your_db_module import get_missing_urls # 替换为你自己实现的从数据库拉取缺失URL的方法 class CategorySpider(CrawlSpider): name = 'categories' # 原有CrawlSpider的rules、allowed_domains等配置全部保留不变 ... @classmethod def from_crawler(cls, crawler, *args, **kwargs): spider = super().from_crawler(crawler, *args, **kwargs) # 绑定空闲信号,爬虫无待处理请求时触发重爬逻辑 crawler.signals.connect(spider.retry_missing_urls, signal=signals.spider_idle) return spider def parse_item(self, response): # 原有解析逻辑完全不用修改 ... yield item def retry_missing_urls(self, spider): if spider != self: return # 从数据库拉取未爬取成功的URL missing_urls = get_missing_urls() for url in missing_urls: # dont_filter=True跳过去重规则,确保重爬请求不会被过滤 yield scrapy.Request( url=url, callback=self.parse_item, dont_filter=True, # 重爬请求单独配置更高的重试次数、代理切换规则等 meta={ 'max_retry_times': 10, 'use_premium_proxy': True } ) return
方案2:保留双爬虫架构,优化维护性+统一触发
如果两套爬取逻辑配置差异大、需要分开管理,用该方案解决现有两个痛点:
第一步:抽离公共逻辑,避免重复代码
将共用的parse_item解析逻辑抽为公共基类,两个爬虫分别继承即可,后续修改解析逻辑只需改一次:
import scrapy from scrapy.spiders import CrawlSpider # 公共解析基类,只维护一套解析逻辑 class BaseCategoryParser: def parse_item(self, response): ... yield item # 常规分类爬虫,同时继承CrawlSpider和公共基类 class CategorySpider(CrawlSpider, BaseCategoryParser): name = 'categories' ... # 无需重复写parse_item方法 # 重爬爬虫,同时继承普通Spider和公共基类 class RecrawlerSpider(scrapy.Spider, BaseCategoryParser): name = 'recrawler' ... # 无需重复写parse_item方法
第二步:同脚本触发双爬虫,无需分开配置cron
用Scrapy官方提供的CrawlerProcess在同一个脚本中顺序启动两个爬虫,只需配置一个cron任务执行该脚本即可:
from scrapy.crawler import CrawlerProcess from scrapy.utils.project import get_project_settings if __name__ == '__main__': settings = get_project_settings() process = CrawlerProcess(settings) # 先启动常规分类爬取 process.crawl(CategorySpider) # 常规爬取跑完后自动启动重爬任务 process.crawl(RecrawlerSpider) process.start()
内容的提问来源于stack exchange,提问作者merlin
相关产品推荐
相关产品推荐

