Scrapy - 使用 JOBDIR 获取重复项

eli*_*ang 5 python csv scrapy

Scrapy 的 JOBDIR 设置提供了可恢复的爬网,描述如下:

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

我尝试像这样执行我的抓取命令:

scrapy crawl myspider -o out.csv -t csv -s JOBDIR=./jobs/run-1
Run Code Online (Sandbox Code Playgroud)

当它仍在运行时,我通过按 CTRL-C 优雅地将其关闭。然后再次启动相同的命令以恢复它。我可以确认它正在从终端输出恢复抓取:

[myspider] INFO: Resuming crawl (74 requests scheduled)
Run Code Online (Sandbox Code Playgroud)

但是当我查看我的输出 CSV 文件时,我看到有这样的重复项:

name,email
Alice,alice@example.com
Bob,bob@example.com
...
name,email            <- duplicated header!
Bob,bob@example.com   <- duplicated row!
...
Run Code Online (Sandbox Code Playgroud)

这是正常的吗?我想知道是否可以在同一个命令中使用-ooption 和JOBDIR。如果没有,我如何导出抓取的项目?

顺便说一句,我正在使用 Scrapy 0.22.1。

谢谢!

yla*_*idi 5

是的,这是可以预料的。如果您查看scrapy的源代码,尤其是CsvItemExporter,您会发现它在停止/恢复抓取方面是无状态的。出口商基本上用 2 个标志处理标头。指示它是否完全包含标题的一个:. 第二个: , 防止每次都转储标头,写入新的抓取项目,会话的第一项除外。但是,每次重新启动爬网程序时,这些标志都会重置,并且导出器似乎不携带有关恢复会话的任何类型的信息: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)
Run Code Online (Sandbox Code Playgroud)

此外 -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)")
Run Code Online (Sandbox Code Playgroud)