【问题标题】:Scrapy creating XML feed wraps content in "value" tagsScrapy 创建 XML 提要将内容包装在“值”标签中
【发布时间】:2015-04-24 23:29:48
【问题描述】:

我的代码在这里得到了一些帮助,非常有效。唯一的问题是,在生成 XML 的过程中,当我不希望它时,它会将内容包装在“值”标签中。根据文档,这是由于:

除非在 :meth:serialize_field 方法中被覆盖,多值 通过序列化 <value> 中的每个值来导出字段 元素。这是为了方便,因为多值字段非常 常见的。

这是我的输出:

<?xml version="1.0" encoding="UTF-8"?>
<items>
   <item>
      <body>
         <value>Don't forget me this weekend!</value>
      </body>
      <to>
         <value>Tove</value>
      </to>
      <who>
         <value>Jani</value>
      </who>
      <heading>
         <value>Reminder</value>
      </heading>
   </item>
</items>

我发给 XML 导出器的好像是这个,所以不知道为什么它认为它是多值的?

{'body': [u"Don't forget me this weekend!"],
 'heading': [u'Reminder'],
 'to': [u'Tove'],
 'who': [u'Jani']}

管道.py

from scrapy import signals
from scrapy.contrib.exporter import XmlItemExporter

class XmlExportPipeline(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_products.xml' % spider.name, 'w+b')
        self.files[spider] = file
        self.exporter = XmlItemExporter(file)
        self.exporter.start_exporting()

    def spider_closed(self, spider):
        self.exporter.finish_exporting()
        file = self.files.pop(spider)
        file.close()

    def process_item(self, item, spider):
        self.exporter.export_item(item)
        return item

蜘蛛.py

from scrapy.contrib.spiders import XMLFeedSpider
from crawler.items import CrawlerItem

class SiteSpider(XMLFeedSpider):
    name = 'site'
    allowed_domains = ['www.w3schools.com']
    start_urls = ['http://www.w3schools.com/xml/note.xml']
    itertag = 'note'

    def parse_node(self, response, selector):
        item = CrawlerItem()
        item['to'] = selector.xpath('//to/text()').extract()
        item['who'] = selector.xpath('//from/text()').extract()
        item['heading'] = selector.xpath('//heading/text()').extract()
        item['body'] = selector.xpath('//body/text()').extract()
        return item

任何帮助将不胜感激。我只想要没有多余标签的相同输出。

【问题讨论】:

    标签: python xml scrapy scrapy-spider


    【解决方案1】:

    extract() 方法将始终返回值列表,即使结果只有一个值,例如:[4][3,4,5]None。 为避免这种情况,如果您知道只有一个值,您可以像这样选择它:

    item['to'] = selector.xpath('//to/text()').extract()[0]
    

    注意: 请注意,如果extract() 返回None 并且您尝试对其进行索引,这可能会导致抛出异常。在这种不确定的情况下,这是一个很好的技巧:

    item['to'] = (selector.xpath('...').extract() or [''])[0]
    

    或者您可以编写自定义函数来获取第一个元素:

    def extract_first(selector, default=None):
        val = selector.extract()
        return val[0] if val else default
    

    这样你可以有一个默认值,以防找不到你想要的值:

    item['to'] = extract_first(selector.xpath(...))  # First or none
    item['to'] = extract_first(selector.xpath(...), 'not-found')  # First of 'not-found'
    

    【讨论】:

      【解决方案2】:

      关于为什么会发生这种情况,上述答案是正确的,但我想补充一点,现在对此提供了开箱即用的支持,无需编写辅助方法。

      item['to'] = selector.xpath('//to/text()').extract_first()
      

      item['to'] = selector.xpath('//to/text()').extract_first(default='spam')
      

      【讨论】:

        猜你喜欢
        • 2015-04-30
        • 2012-09-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-05-09
        • 1970-01-01
        • 2014-05-03
        相关资源
        最近更新 更多