Scrapy - 使用JOBDIR获取重复项目

5 投票
1 回答
840 浏览
提问于 2025-04-17 21:09

Scrapy的JOBDIR设置可以让你在爬虫中断后继续爬取,具体说明可以在这里找到:

http://doc.scrapy.org/en/latest/topics/jobs.html

我尝试这样执行我的爬虫命令:

scrapy crawl myspider -o out.csv -t csv -s JOBDIR=./jobs/run-1

在爬虫还在运行的时候,我通过按CTRL-C优雅地关闭它。然后再执行同样的命令来继续爬取。我可以从终端的输出中确认它确实是从之前的地方继续爬取的:

[myspider] INFO: Resuming crawl (74 requests scheduled)

但是当我查看输出的CSV文件时,发现里面有重复的项目,如下所示:

name,email
Alice,alice@example.com
Bob,bob@example.com
...
name,email            <- duplicated header!
Bob,bob@example.com   <- duplicated row!
...

这是正常现象吗?我在想,是否可以在同一个命令中同时使用-o选项和JOBDIR。如果不可以,那我该如何导出爬取到的项目呢?

顺便说一下,我使用的是Scrapy 0.22.1。

谢谢!

1 个回答

5

是的,这种情况是可以预料的。如果你查看一下scrapy的源代码,特别是CsvItemExporter,你会发现它在停止恢复爬虫时是无状态的。这个导出器主要通过两个标志来处理表头。一个标志是用来指示是否包含表头:include_headers_line。另一个标志是_headers_not_written,它可以防止每次写入新的抓取项时都重复写入表头,除了会在会话的第一个项目时写入表头。不过,这些标志在每次重新启动爬虫时都会被重置,导出器似乎不会保存任何关于恢复会话的信息。

class CsvItemExporter(BaseItemExporter):

    def __init__(self, file, include_headers_line=True, join_multivalued=',', **kwargs):

        ....
        self._headers_not_written = True
        ....

    def export_item(self, item):
        if self._headers_not_written:
            self._headers_not_written = False
            self._write_headers_and_set_fields_to_export(item)

另外,-o选项只是告诉爬虫将抓取到的项目输出到指定的地方,并没有其他的作用:

class Command(ScrapyCommand):

    ....

    def add_options(self, parser):
        ScrapyCommand.add_options(self, parser)
        parser.add_option("-a", dest="spargs", action="append", default=[], metavar="NAME=VALUE", \
            help="set spider argument (may be repeated)")
        parser.add_option("-o", "--output", metavar="FILE", \
            help="dump scraped items into FILE (use - for stdout)")
        parser.add_option("-t", "--output-format", metavar="FORMAT", default="jsonlines", \
            help="format to use for dumping items with -o (default: %default)")

撰写回答