如何将Scrapy爬取数据存入变量而非文件/数据库并按需调用
实现方法
你现有代码的问题是多进程封装仅做了异常传递,没有把爬虫产出的爬取结果从子进程回传到主进程,因此调用时拿不到数据。只要做两处调整即可实现「调用即触发爬虫、直接在内存处理爬取结果、无需落盘存储」的需求:
- 给爬虫注册一个内存级的临时Item Pipeline,所有Spider yield的item直接暂存到内存列表,不配置任何文件/数据库存储的Pipeline
- 修改多进程队列的传递逻辑,把爬取完成后收集到的结果随队列返回主进程,调用函数时直接拿到结果对象
完整可运行代码
import scrapy import scrapy.crawler as crawler from scrapy.utils.log import configure_logging from multiprocessing import Process, Queue from twisted.internet import reactor # 原有Spider逻辑无需修改 class QuotesSpider(scrapy.Spider): name = "quotes" start_urls = ['http://quotes.toscrape.com/tag/humor/'] def parse(self, response): yield {"html_data": response.text} def run_spider(spider_cls): def _crawl_in_subprocess(q): try: collected_items = [] # 临时Pipeline:仅做内存收集,不做任何落盘操作 class MemoryCollectPipeline: def process_item(self, item, spider): collected_items.append(dict(item)) return item # 初始化Runner时仅注册内存收集Pipeline,禁用所有默认存储逻辑 runner = crawler.CrawlerRunner(settings={ "ITEM_PIPELINES": { "__main__._crawl_in_subprocess.<locals>.MemoryCollectPipeline": 100 } }) deferred = runner.crawl(spider_cls) deferred.addBoth(lambda _: reactor.stop()) reactor.run() # 爬取完成后把结果传回主进程 q.put({"items": collected_items, "error": None}) except Exception as e: q.put({"items": None, "error": e}) msg_queue = Queue() crawl_process = Process(target=_crawl_in_subprocess, args=(msg_queue,)) crawl_process.start() process_result = msg_queue.get() crawl_process.join() if process_result["error"]: raise process_result["error"] # 直接返回爬取到的所有结构化数据 return process_result["items"] if __name__ == "__main__": configure_logging() # 调用函数即触发爬虫运行,直接拿到所有爬取结果 crawl_result = run_spider(QuotesSpider) # 直接在内存处理数据,无需读写文件/数据库 print(f"爬取完成,共获取{len(crawl_result)}条数据") for single_item in crawl_result: print(f"单条页面HTML长度:{len(single_item['html_data'])}")
注意事项
- 所有启动逻辑必须放在
if __name__ == "__main__":代码块内,避免Windows平台多进程递归启动的报错,跨平台运行稳定性更好 - 该封装支持重复调用,每次调用
run_spider都会启动独立子进程运行爬虫,规避了Twisted reactor无法在同进程内重复启动的问题 - 如果需要给爬虫传参(比如自定义爬取页码、起始URL),直接在
runner.crawl(spider_cls, key=value)位置传入参数即可,和Scrapy原生传参逻辑完全一致 - 爬取的数据量极大时不建议用这个方案,内存占用会随爬取数据量上涨,普通小规模爬取、实时处理场景完全适用
内容的提问来源于stack exchange,提问作者imhans4305
相关产品推荐
相关产品推荐

