CrawlerProcess中仅一个Spider触发ItemPipeline的原因排查
先梳理下你的问题:两个独立的Scrapy Spider,ResourceCrawler能正常触发MongoDB Pipeline,但CampusCoursesCrawler不行,且Item在ItemLoader处理前数据是正常的。结合你的代码,我按优先级列出几个最可能的原因和排查方向:
1. CourseItem未显式声明Spider字段
Scrapy的Item类需要显式定义所有要使用的字段,如果你的CourseItem里没有添加Spider = Field(),哪怕用ItemLoader添加了这个值,load_item()后也不会保留该字段。这会导致Pipeline的select_document方法访问item['Spider']时抛出KeyError,直接中断Item的存储流程。
排查修复:
打开CourseItem的定义文件,确认包含该字段:
from scrapy.item import Item, Field class CourseItem(Item): # 你的其他字段... Spider = Field() # 必须显式声明
2. CampusCoursesCrawler的name属性不匹配Pipeline判断条件
你的Pipeline里判断item['Spider'] == 'courses_crawler'才会映射到Courses集合,但如果CampusCoursesCrawler类的name属性不是'courses_crawler'(比如是'CampusCoursesCrawler'),那l.add_value('Spider', self.name)就会写入错误标识,导致select_document无法匹配到正确的集合和键。
排查修复:
检查CampusCoursesCrawler的定义:
class CampusCoursesCrawler(scrapy.Spider): name = 'courses_crawler' # 必须和Pipeline里的判断值完全一致 # 其他属性...
3. populate_db方法的返回值未被yield
你的populate_db方法返回了加载后的Item,但如果调用它的parse方法里没有用yield抛出这个Item,Scrapy就不会把Item发送到Pipeline处理。比如错误写法:
def parse(self, response): # 处理data逻辑... self.populate_db(response, data) # 仅返回不yield,Item不会进入Pipeline
正确写法应该是:
def parse(self, response): # 处理data逻辑... yield self.populate_db(response, data) # 必须yield才能触发Pipeline
4. Pipeline的process_item方法未返回Item
Scrapy要求每个Pipeline的process_item方法必须返回Item对象(或抛出DropItem异常),否则Item会被丢弃,后续流程中断。你的当前代码里process_item没有返回语句,虽然ResourceCrawler可能侥幸工作,但这不符合规范,可能导致CampusCoursesCrawler的Item无法正常流转。
修复方法:在process_item末尾添加返回:
def process_item(self, item, spider): document, key = self.select_document(item, spider) self.client.Campus[document].update({key : item[key]}, {'$set': item}, upsert=True) return item # 必须返回Item,保证流程继续
5. 未捕获的异常导致Pipeline处理失败
如果前面的问题都排查过了,那可能是Pipeline处理CourseItem时抛出了未被捕获的异常(比如select_document返回None导致的解包错误、MongoDB连接异常等)。这时候需要开启Scrapy的DEBUG日志查看具体错误。
排查方法:
在CrawlerProcess的配置中添加日志级别:
process = CrawlerProcess({ 'USER_AGENT': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36', 'ITEM_PIPELINES': {'CampusScraper.pipelines.Item_to_MongoDB': 100}, 'LOG_LEVEL': 'DEBUG' # 开启DEBUG日志,查看详细错误信息 })
运行程序后检查日志,是否有KeyError、ValueError或MongoDB相关的报错。
6. Pipeline的close_spider方法参数错误
虽然这个问题不直接影响Item存储,但会导致Spider关闭时抛出异常,建议一并修复:close_spider方法需要接收spider参数,你的当前代码缺少该参数,修改为:
def close_spider(self, spider): # 添加spider参数 self.client.close()
内容的提问来源于stack exchange,提问作者Christoph Zangerle

