【问题标题】:scrapyd multiple spiders writing items to same filescrapyd 多个蜘蛛将项目写入同一个文件
【发布时间】:2016-07-11 00:18:25
【问题描述】:

我有多个蜘蛛同时运行的scrapyd服务器,我使用schedule.json端点一一启动蜘蛛。所有蜘蛛都使用管道将内容写入公共文件

class JsonWriterPipeline(object):

def __init__(self, json_filename):
    # self.json_filepath = json_filepath
    self.json_filename = json_filename
    self.file = open(self.json_filename, 'wb')

@classmethod
def from_crawler(cls, crawler):
    save_path='/tmp/'
    json_filename=crawler.settings.get('json_filename', 'FM_raw_export.json')
    completeName = os.path.join(save_path, json_filename) 
    return cls(
        completeName
    )

def process_item(self, item, spider):
    line = json.dumps(dict(item)) + "\n"
    self.file.write(line)
    return item

蜘蛛运行后,我可以看到它们如何正确收集数据,项目存储在 XXXX.jl 文件中,并且蜘蛛正常工作,但是爬取的内容没有反映在公共文件上。 Spiders 似乎运行良好,但管道并没有很好地完成它们的工作,并且没有将数据收集到公共文件中。

我还注意到只有一个蜘蛛同时在文件上写。

【问题讨论】:

    标签: scrapy scrapy-spider scrapyd scrapy-pipeline


    【解决方案1】:

    我看不出有什么好的理由去做你所做的事情 :) 你可以通过在你的 scrapyd schedule.json 请求上设置参数来更改 json_filename 设置。然后,您可以让每个蜘蛛生成稍微不同的文件,您可以在后处理或查询时合并这些文件。您还可以通过设置 FEED_URI 值 (example) 来编写类似于您所拥有的 JSON 文件。如果您同时从多个进程写入单个文件(尤其是当您使用'wb' 模式打开时),您正在寻找损坏的数据。

    编辑:

    在更好地了解您需要什么之后 - 在这种情况下 - 它是 scrapyd 开始运行不同蜘蛛的多次爬网,其中每个爬网爬取不同的网站。消费者进程持续监控单个文件。

    有几种解决方案,包括:

    • 命名管道

    相对容易实现,仅适用于非常小的项目 (see here)

    • RabbitMQ 或其他一些排队机制

    很好的解决方案,但可能有点矫枉过正

    • 一个数据库,例如基于 SQLite 的解决方案

    不错且简单,但可能需要一些编码(自定义使用者)

    • 一个不错的基于inotifywait 或其他文件系统监控解决方案

    很好,很容易实现

    最后一个对我来说似乎是最有吸引力的选择。当scrapy crawl 完成时(spider_closed signal),将FEED_URL 文件移动、复制或创建软链接到您使用this 之类的脚本监视的目录。 mvln 是一个原子 unix 操作,所以你应该没问题。修改脚本以将新文件附加到您的 tmp 文件中,您曾经将它提供给您的消费者程序。

    通过这种方式,您可以使用默认的 Feed 导出器来编写文件。最终解决方案非常简单,您不需要管道。一个简单的扩展应该符合要求。

    在与settings.py 在同一目录中的extensions.py 上:

    from scrapy import signals
    from scrapy.exceptions import NotConfigured
    
    class MoveFileOnCloseExtension(object):
    
        def __init__(self, feed_uri):
            self.feed_uri = feed_uri
    
        @classmethod
        def from_crawler(cls, crawler):
            # instantiate the extension object
            feed_uri = crawler.settings.get('FEED_URI')
            ext = cls(feed_uri)
    
            crawler.signals.connect(ext.spider_closed, signal=signals.spider_closed)
    
            # return the extension object
            return ext
    
        def spider_closed(self, spider):
            # Move the file to the proper location
            # os.rename(self.feed_uri, ... destination path...)
    

    在你的settings.py

    EXTENSIONS = {
        'myproject.extensions.MoveFileOnCloseExtension': 500,
    }
    

    【讨论】:

    • 感谢您的回答。我想我不太了解管道如何在scrapy中工作。据我了解,蜘蛛生成项目,所有蜘蛛的项目都传递给管道,对它们都是全局的,并处理它们。根据您的回答,我猜每个蜘蛛都有自己的管道,并且有多个管道使用同一个文件,这会造成麻烦。我对吗? .我这样做是因为有另一个进程对内容做一些事情并且只接受一个文件。
    • 措辞不是 100% 准确,但您说的是对的。更具体地说,scrapyd 并行运行多个scrapy 进程。每个scrapy 进程运行一个蜘蛛和你的管道。这意味着在进行此爬网时,您将打开同一个文件以从许多进程中写入,这将导致损坏。 “...只接受一个文件”。我确信有更好的方法来做到这一点。你可以运行scrapyd吗,例如100 个文件,concat them to one,然后将其提供给您的流程?这种情况更为常见。
    • 你知道一些选项可以将所有蜘蛛的结果(项目)放在同一个文件中,只使用scrapy吗?谢谢
    • 谢谢,我会发邮件给你删除
    • 感谢更新的答案。我喜欢你提出的建议,我会选择你提出的解决方案或兔子方案。 Rabbit 有另一个优势,如果我需要将蜘蛛放在不同的服务器上,因为缩放建议很容易做到,而且我将来可能会发生。但无论如何,为了简单起见,我将使用扩展程序或为了鲁棒性和可扩展性而使用兔子。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-21
    • 2018-07-04
    相关资源
    最近更新 更多