首页 > 解决方案 > 如何将 Scrapy 管道中的批量更新写入 mongodb

问题描述

我有一个基于 Scrapy 的持续运行的爬虫。

在每次运行中,此爬虫都会对给定 ID 列表执行请求,并将输出写入 S3 存储桶。

这些请求可能会不时失败,我需要记录成功和失败。

我目前正在产生一个成功的项目和一个特殊的 ErrorItem 失败。

我制作了一个应该处理成功和失败日志的管道。

def process_item(self, item, spider):
    if isinstance(item, MyErrorItem):
        self.errors.append(item['id'])
        raise DropItem('Dropped')
    else:
        self.success.append(item['id'])
        return item

def close_spider(self, spider):
    conn_to_mongo = getconn()
    errors_query = create_or_query_by_ids(self.errors)
    write_to_mongo(errors_query, {"$set": {"status": "fail"}})
    success_query = create_or_query_by_ids(self.success)
    write_to_mongo(success_query, {"$set": {"status": "success"}})

我没有找到对这种模式的任何参考。通常所有对外部数据引擎的写入都是由 process_item 函数完成的。

在这里,我将 id 收集到相应的列表中,并在 close_spider 上批量写入。

原因是对数据库执行多个写入请求是没有效率的,如果这可以批量完成的话。

是否有更有效的方法来实现这种行为?这种方法有什么陷阱吗?

标签: pythonmongodbscrapy

解决方案


我不认为这种方法有什么大问题。我能想到的一些缺点:

  • 您在内存中保留 2 个列表,这些列表在蜘蛛运行时会不断增长。如果列表变大,这可能会成为问题。如果您逐项进行插入,则不会有这个。
  • 如果最后插入错误,您将丢失所有已抓取的数据。例如,如果在您要插入数据时数据库不可用或过载,则必须再次运行蜘蛛

我认为更好的方法可能如下:

  • 项目管道写入 json 文件而不是附加到列表
  • 在关闭蜘蛛时,您基于 json 文件而不是列表进行插入

这样你就不会超载内存,如果最后插入失败,你可以根据文件重试它,而不必再次重新运行所有内容。


推荐阅读