【问题标题】:Using normalize-space with Scrapy在 Scrapy 中使用规范化空间
【发布时间】:2016-02-27 12:11:44
【问题描述】:

下面是我正在处理的文档的模型:

<div>
<h4>Area</h4>
  <span class="aclass"> </span>
  <span class="bclass">
        <strong>Address:</strong>
  10 Downing Street

  London

  SW1
  </span>
</div>

我得到这样的地址:

response.xpath(u".//h4[. = 'Area']/following-sibling::span[contains(.,'Address:')]/text()").extract()

返回

[u'\r\n  \t', u'\r\n  10 Downing Street\r\n\r\n  London     \r\n  \r\n  SW1\r\n  ']

我正在尝试使用 normalize-space 来清理它。我试过把它放在我能想到的每个位置,但它要么告诉我有语法错误,要么返回一个空字符串。

更新以补充说我正在尝试在不过多更改选择器的情况下使其正常工作。例如,我有类似的案例没有&lt;strong&gt; 标签。选择器在我在这里准备的示例中过于复杂,但在实际版本中,我必须采取相当复杂的路线才能到达地址。

关于可能的重复项根据可能重复项中的建议,我添加了/normalize-space(.),给出了这个:

(u".//h4[. = 'Area']/following-sibling::span[contains(.,'Address:')]/text()/normalize-space(.)").extract()

这会产生ValueError: Invalid XPath: 错误。

【问题讨论】:

  • 关于重复问题参考:.//h4[. = 'Area']/following-sibling::span[contains(.,'Address:')]/text()/normalize-space(.) 在 XPath 2 中有效,但 在 XPath 1.0 中无效(仅在 lxml/libxml2 之上,scrapy 支持)。引用已接受的答案there“在 XPath 2.0 中,XPath 表达式的定位步骤可能是函数引用”。这在 XPath 1.0 中是不可能的
  • 另一种选择是在&lt;span&gt; 上使用normalize-space()string() 和地址,并使用正则表达式链接.re(r)r=re.compile(r'Address:(.*)', re.S) 或类似的。 selector.xpath('.//h4[.="Area"]/following-sibling::span[starts-with(normalize-space(), "Address")]').xpath('string()').re(r) 会给你[u'\n 10 Downing Street\n\n London\n\n SW1\n '](我使用string() 因为换行很重要,normalize-space() 会用空格替换它们)

标签: python parsing xpath web-scraping scrapy


【解决方案1】:

您可以找到strong 元素,获取以下文本兄弟并对其进行规范化:

In [1]: response.xpath(u"normalize-space(.//strong[. = 'Address:']/following-sibling::text())").extract()
Out[1]: [u'10 Downing Street London SW1']

或者,您可以查看Item Loaders 以及输入和输出处理器。我经常使用Join()TakeFirst()MapCompose(unicode.strip) 来清理从多余的换行符或空格中提取的数据。

【讨论】:

  • 我觉得,根据您对数据的处理方式,项目加载器将是可行的方法。这是它旨在做的主要事情之一 - 数据清理/格式化。
【解决方案2】:
"normalize-space(//strong[contains(text(), 'Address:')]/following-sibling::node())"

【讨论】:

  • 您回答的原始版本与此类似: (u"normalize-space(//h4[. = 'Area']/following-sibling::span[contains(.,'Address :')])").extract() 这实际上似乎有效。我只是想知道你是否看到了一个特别的问题。有什么理由不使用它吗?
【解决方案3】:

由于您使用的是 Scrapy,您可以使用 Python 单线器来简化您的 XPath:

" ".join(s.split()) # where `s` is your string

使用上述方法,您可以从 XPath 表达式中省略 normalize-space,而是使用 Scrapy Input Processors 创建一个可重用的清理函数,如下所示:

import scrapy
from scrapy.loader.processors import MapCompose
from w3lib.html import remove_tags

def normalize_space(value):
    return " ".join(value.split())

class Product(scrapy.Item):
    name = scrapy.Field(
        input_processor=MapCompose(remove_tags, normalize_space),
    )

或者,您也可以在 Scrapy Item Loader 中使用 Python 表达式,如下所示:

import scrapy
from scrapy.loader import ItemLoader
from scrapy.loader.processors import Compose

class ProductLoader(ItemLoader):
    name_in = Compose(lambda s: " ".join(s.split()))

在一个相关问题中,单线的功劳转到Tom's answer

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-06
    • 1970-01-01
    • 2018-03-12
    • 1970-01-01
    相关资源
    最近更新 更多