抓取时如何避免加入节点中的所有文本

Posted

技术标签:

【中文标题】抓取时如何避免加入节点中的所有文本【英文标题】:How to avoid joining all text from Nodes when scraping 【发布时间】:2020-05-28 10:08:50 【问题描述】:

当我从 html 或 XML 中抓取多个相关节点以提取文本时,所有文本都连接成一个长字符串,因此无法恢复单个文本字符串。

例如:

require 'nokogiri'

doc = Nokogiri::HTML(<<EOT)
<html>
  <body>
    <p>foo</p>
    <p>bar</p>
    <p>baz</p>
  </body>
</html>
EOT

doc.search('p').text # => "foobarbaz"

但我想要的是:

["foo", "bar", "baz"]

抓取 XML 时也会发生同样的情况:

doc = Nokogiri::XML(<<EOT)
<root>
  <block>
    <entries>foo</entries>
    <entries>bar</entries>
    <entries>baz</entries>
  </block>
</root>
EOT

doc.search('entries').text # => "foobarbaz"

为什么会发生这种情况,我该如何避免?

【问题讨论】:

【参考方案1】:

这是一个很容易解决的问题,因为没有阅读有关 text 在 NodeSet 与 Node(或 Element)上使用时的行为方式的文档。

NodeSet documentation 表示text 将:

获取所有包含的 Node 对象的内部文本

我们看到的情况是这样的:

doc = Nokogiri::HTML(<<EOT)
<html>
  <body>
    <p>foo</p>
    <p>bar</p>
    <p>baz</p>
  </body>
</html>
EOT

doc.search('p').text # => "foobarbaz"

因为:

doc.search('p').class # => Nokogiri::XML::NodeSet

相反,我们想要获取每个节点并提取其文本:

doc.search('p').first.class # => Nokogiri::XML::Element
doc.search('p').first.text # => "foo"

这可以使用map:

doc.search('p').map  |node| node.text  # => ["foo", "bar", "baz"]

Ruby 允许我们使用以下代码更简洁地编写它:

doc.search('p').map(&:text) # => ["foo", "bar", "baz"]

无论我们使用 HTML 还是 XML,同样的事情都适用,因为 HTML 是 XML 的更宽松版本。

一个节点有几个别名方法来获取它的嵌入文本。来自the documentation:

#content ⇒ Object

也称为:textinner_text

返回此节点的内容。

【讨论】:

以上是关于抓取时如何避免加入节点中的所有文本的主要内容,如果未能解决你的问题,请参考以下文章

PXC加入新节点避免SST时grastate.dat文件内容的修改问题

Cytoscape js在节点上单击时如何获取所有边缘(文本标签)

Charles抓取请求中的图片

使用python如何摆脱从网站上抓取的文本中的尾随空格[重复]

如何在python中的id =“ firstheading”之后抓取网页上的所有信息?

如何使用 XSL 选择特定元素节点中的所有文本节点?