【问题标题】:Custom scrapy xml+rss exporter to S3自定义 scrapy xml+rss 导出器到 S3
【发布时间】:2016-07-09 07:19:46
【问题描述】:

我正在尝试创建一个自定义 xml 提要,它将包含蜘蛛抓取的项目以及一些其他高级信息,存储在蜘蛛定义中。输出应存储在 S3 上。

所需的输出如下所示:

<xml>
  <title>my title defined in the spider</title>
  <description>The description from the spider</description>
  <items>
    <item>...</item>
  </items>
</xml>

为此,我定义了一个自定义导出器,它能够在本地导出所需的输出文件。

spider.py:

class DmozSpider(scrapy.Spider):
    name = 'dmoz'
    allowed_domains = ['dmoz.org']
    start_urls = ['http://www.dmoz.org/Computers/']
    title = 'The DMOZ super feed'

    def parse(self, response):
        ...
        yield item

exporters.py:

from scrapy.conf import settings

class CustomItemExporter(XmlItemExporter):

    def __init__(self, *args, **kwargs):
        self.title = kwargs.pop('title', 'no title found')
        self.link = settings.get('FEED_URI', 'localhost')
        super(CustomItemExporter, self).__init__(*args, **kwargs)

    def start_exporting(self):
       ...
       self._export_xml_field('title', self.title)
       ...

settings.py:

FEED_URI = 's3://bucket-name/%(name)s.xml'
FEED_EXPORTERS = {
    'custom': 'my.exporters.CustomItemExporter',
}

我可以运行整个程序并通过运行以下命令在 s3 上获得输出:

scrapy crawl dmoz -t custom

或者,如果我想在本地导出 json:scrapy crawl -o dmoz.json dmoz

但此时,我无法检索蜘蛛标题以将其放入输出文件中。

我尝试实现一个自定义管道,它在本地输出数据(遵循大量示例):

pipelines.py:

class CustomExportPipeline(object):

    def __init__(self):
        self.files = {}

    @classmethod
    def from_crawler(cls, crawler):
         pipeline = cls()
         crawler.signals.connect(pipeline.spider_opened, signals.spider_opened)
         crawler.signals.connect(pipeline.spider_closed, signals.spider_closed)
         return pipeline

    def spider_opened(self, spider):
        file = open('%s_feed.xml' % spider.name, 'w+b') 
        self.files[spider] = file
        self.exporter = CustomItemExporter(
            file,
            title = spider.title),
        )
        self.exporter.start_exporting()

问题是,文件存储在本地,这会使处理所有不同存储的 feedexport.py 中定义的 FeedExporter 逻辑短路。 管道中没有来自 FeedExporter 的信息,我想在不重复代码的情况下重用所有这些逻辑。我错过了什么吗?感谢您的帮助。

【问题讨论】:

    标签: scrapy


    【解决方案1】:

    这是我的解决方案:

    1. 摆脱管道。
    2. 覆盖 scrapy 的 FeedExporter

      myproject/feedexport.py:

      from scrapy.extensions.feedexport import FeedExporter as _FeedExporter
      from scrapy.extensions.feedexport import SpiderSlot
      
      class FeedExporter(_FeedExporter):
      
          def open_spider(self, spider):
              uri = self.urifmt % self._get_uri_params(spider)
              storage = self._get_storage(uri)
              file = storage.open(spider)
              extra = { 
                  # my extra settings
              }
              exporter = self._get_exporter(file, fields_to_export=self.export_fields, extra=extra)
              exporter.start_exporting()
              self.slot = SpiderSlot(file, exporter, storage, uri)
      

      我想做的基本上就是将这些额外的设置传递给导出器,但是它的构建方式,除了覆盖别无选择。 为了同时支持其他 scrapy 导出格式,我不得不考虑在一些 scrapy 导出器中将 dont_fail 设置覆盖为 True 以防止它们失败

    3. 用新的替换 scrapy 的 feed 导出器

      myproject/feedexport.py:

      EXTENSIONS = {
          'scrapy.extensions.feedexport.FeedExporter': None,
          'myproject.feedexport.FeedExporter': 0,
      }
      

      ...或者 2 个 Feed 导出器将同时运行

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多