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

Scrapy运行报错:cannot pickle 'module' object 问题求助

解决Scrapy中MongoDBPipeline引发的TypeError: cannot pickle 'module' object错误

问题场景

按照RealPython的《使用Scrapy和MongoDB进行网络爬取》教程操作时,运行Scrapy代码触发以下错误:

File "/home/nawalnaz/miniconda3/bin/scrapy", line 8, in <module>
    sys.exit(execute())
             ^^^^^^^^^
  File "/home/nawalnaz/miniconda3/lib/python3.11/site-packages/scrapy/cmdline.py", line 160, in execute
    cmd.crawler_process = CrawlerProcess(settings)
                          ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/nawalnaz/miniconda3/lib/python3.11/site-packages/scrapy/crawler.py", line 357, in __init__
    super().__init__(settings)
  File "/home/nawalnaz/miniconda3/lib/python3.11/site-packages/scrapy/crawler.py", line 227, in __init__
    self.spider_loader = self._get_spider_loader(settings)
                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/nawalnaz/miniconda3/lib/python3.11/site-packages/scrapy/crawler.py", line 221, in _get_spider_loader
    return loader_cls.from_settings(settings.frozencopy())
                                    ^^^^^^^^^^^^^^^^^^^^^
  File "/home/nawalnaz/miniconda3/lib/python3.11/site-packages/scrapy/settings/__init__.py", line 470, in frozencopy
    copy = self.copy()
           ^^^^^^^^^^^
  File "/home/nawalnaz/miniconda3/lib/python3.11/site-packages/scrapy/settings/__init__.py", line 452, in copy
    return copy.deepcopy(self)
           ^^^^^^^^^^^^^^^^^^^
  File "/home/nawalnaz/miniconda3/lib/python3.11/copy.py", line 172, in deepcopy
    y = _reconstruct(x, memo, *rv)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/nawalnaz/miniconda3/lib/python3.11/copy.py", line 271, in _reconstruct
    state = deepcopy(state, memo)
            ^^^^^^^^^^^^^^^^^^^^^
  File "/home/nawalnaz/miniconda3/lib/python3.11/copy.py", line 146, in deepcopy
    y = copier(x, memo)
        ^^^^^^^^^^^^^^^
  File "/home/nawalnaz/miniconda3/lib/python3.11/copy.py", line 231, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
                             ^^^^^^^^^^^^^^^^^^^^^
  File "/home/nawalnaz/miniconda3/lib/python3.11/copy.py", line 146, in deepcopy
    y = copier(x, memo)
        ^^^^^^^^^^^^^^^
  File "/home/nawalnaz/miniconda3/lib/python3.11/copy.py", line 231, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
                             ^^^^^^^^^^^^^^^^^^^^^
  File "/home/nawalnaz/miniconda3/lib/python3.11/copy.py", line 172, in deepcopy
    y = _reconstruct(x, memo, *rv)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/nawalnaz/miniconda3/lib/python3.11/copy.py", line 271, in _reconstruct
    state = deepcopy(state, memo)
            ^^^^^^^^^^^^^^^^^^^^^
  File "/home/nawalnaz/miniconda3/lib/python3.11/copy.py", line 146, in deepcopy
    y = copier(x, memo)
        ^^^^^^^^^^^^^^^
  File "/home/nawalnaz/miniconda3/lib/python3.11/copy.py", line 231, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
                             ^^^^^^^^^^^^^^^^^^^^^
  File "/home/nawalnaz/miniconda3/lib/python3.11/copy.py", line 161, in deepcopy
    rv = reductor(4)
         ^^^^^^^^^^^
TypeError: cannot pickle 'module' object

问题代码定位

经排查,错误源于MongoDBPipeline类的初始化代码:

class MongoDBPipeline(object):
    def __init__(self):
        connection = pymongo.MongoClient(
            settings['MONGODB_SERVER'],
            settings['MONGODB_PORT']
        )
        db = connection[settings['MONGODB_DB']]
        self.collection = db[settings['MONGODB_COLLECTION']]

修复方案

问题核心是直接引用了全局的settings模块对象,而Scrapy在处理设置时会尝试深拷贝操作,模块对象无法被序列化/深拷贝。改用Scrapy推荐的from_crawler类方法获取设置即可解决:

import pymongo
from scrapy.utils.project import get_project_settings

class MongoDBPipeline(object):
    @classmethod
    def from_crawler(cls, crawler):
        # 通过crawler实例安全获取项目设置
        settings = crawler.settings
        pipeline = cls()
        # 初始化MongoDB连接与集合
        connection = pymongo.MongoClient(
            settings.get('MONGODB_SERVER'),
            settings.get('MONGODB_PORT')
        )
        db = connection[settings.get('MONGODB_DB')]
        pipeline.collection = db[settings.get('MONGODB_COLLECTION')]
        return pipeline

    def __init__(self):
        # 保留空初始化方法,避免实例化报错
        self.collection = None

关键说明

  • from_crawler是Scrapy官方推荐的Pipeline初始化方式,能避免直接引用全局模块导致的序列化问题;
  • 使用settings.get()替代直接索引settings[],可避免因配置键不存在引发的KeyError,代码更健壮。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 07:36:08