You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Django中集成Scrapy爬虫与同步SDK,无法获取Scrapy爬虫结果的问题求助

问题分析与解决方案

首先,你的核心问题出在两个地方:多进程内存隔离和Twisted Reactor的不当处理,导致你无法从Scrapy爬虫中获取结果。让我一步步拆解并解决:

1. 核心问题根源

  • 多进程内存隔离:你传递给子进程的普通result列表,在子进程中是独立的内存拷贝——子进程里append的内容不会同步到父进程的列表中,所以父进程最终拿到的还是空列表。
  • Twisted Reactor处理错误:你用inlineCallbacks的方式没有正确等待爬虫完成,而且reactor.run()的停止逻辑不够严谨,可能导致爬虫还没完成就退出了。

2. 修复方案:使用进程安全的共享容器

我们可以用multiprocessing.Manager创建进程安全的共享列表,让子进程的修改能被父进程感知到。同时修正Scrapy爬虫和多进程的实现逻辑:

修改后的完整代码

1. 爬虫解析器类 (scrapyParser)

from multiprocessing import Process, Manager

class scrapyParser(Parser):
    def __init__(self, keywords=None, n_items=None):
        super().__init__(keywords, n_items)
    
    def parse(self):
        if not super().parse():
            return False
        
        # 使用Manager创建进程安全的共享列表
        with Manager() as manager:
            shared_result = manager.list()
            crawler = UrlCrawlerScript(shared_result, [BASE_PATH + self.keywords])
            crawler.start()
            crawler.join()  # 等待子进程完全结束
            
            # 转换为普通列表后返回前n条结果
            return list(shared_result)[:self.n_items]

2. 多进程爬虫执行类 (UrlCrawlerScript)

from twisted.internet import reactor
from scrapy.crawler import Crawler
from scrapy import signals
from scrapy.utils.project import get_project_settings

class UrlCrawlerScript(Process):
    def __init__(self, shared_result, urls):
        super().__init__()
        self.shared_result = shared_result
        self.urls = urls
        self.settings = get_project_settings()
        self.spider_cls = Parser1  # 关联你的爬虫类
    
    def run(self):
        # 创建Crawler实例
        crawler = Crawler(self.spider_cls, self.settings)
        
        # 绑定信号:爬虫关闭时停止Reactor
        crawler.signals.connect(reactor.stop, signal=signals.spider_closed)
        
        # 启动爬虫,传入共享列表作为结果容器
        crawler.crawl(self.spider_cls, outputResponse=self.shared_result, start_urls=self.urls)
        
        # 运行Reactor直到爬虫完成
        reactor.run()
        # 确保Reactor彻底停止,避免资源泄漏
        reactor.stop()

3. Scrapy爬虫类 (Parser1)

import scrapy

class Parser1(scrapy.Spider):
    name = 'items'
    allowed_domains = ['domain.com']
    
    # 初始化时接收共享列表和起始URL
    def __init__(self, outputResponse=None, start_urls=None, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.outputResponse = outputResponse
        self.start_urls = start_urls or []

    def parse(self, response):
        # 你的页面解析逻辑(示例)
        row_data = response.css('your-target-selector')
        for item in row_data:
            scraped_info = {
                'title': item.css('h2::text').get().strip(),
                'url': item.css('a::attr(href)').get(),
                # 其他字段根据你的需求补充
            }
            # 将结果写入共享列表
            if self.outputResponse is not None:
                self.outputResponse.append(scraped_info)

3. 更简单的替代方案:避免多进程

如果你的场景不需要多进程(比如爬虫耗时不长),可以直接在主线程用CrawlerRunner运行Scrapy,彻底规避多进程共享的问题,更适合Django同步视图的场景:

from scrapy.crawler import CrawlerRunner
from twisted.internet import reactor

class scrapyParser(Parser):
    def __init__(self, keywords=None, n_items=None):
        super().__init__(keywords, n_items)
    
    def parse(self):
        if not super().parse():
            return False
        
        result = []
        runner = CrawlerRunner(get_project_settings())
        
        # 定义爬虫完成后的回调:停止Reactor
        def on_finish(_):
            reactor.stop()
        
        # 启动爬虫
        deferred = runner.crawl(Parser1, outputResponse=result, start_urls=[BASE_PATH + self.keywords])
        deferred.addCallback(on_finish)
        
        # 运行Reactor直到爬虫结束
        reactor.run()
        
        return result[:self.n_items]

4. 关键注意事项

  • 进程安全容器:Manager.list()是进程安全的,保证子进程的修改能被父进程读取;普通列表在多进程中是独立拷贝,无法共享状态。
  • Reactor管理:无论用哪种方式,都要确保爬虫完成后正确停止Reactor,避免资源泄漏或程序挂起。
  • Scrapy配置:确保get_project_settings()能正确加载你的Scrapy项目配置(比如settings.py中的ROBOTSTXT_OBEY、USER_AGENT等设置)。

内容的提问来源于stack exchange,提问作者sphinks

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 07:12:45