抓取时如何避免连接节点中的所有文本

the*_*Man 2 html ruby xml parsing nokogiri

当我从 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"
Run Code Online (Sandbox Code Playgroud)

但我想要的是:

["foo", "bar", "baz"]
Run Code Online (Sandbox Code Playgroud)

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

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

doc.search('entries').text # => "foobarbaz"
Run Code Online (Sandbox Code Playgroud)

为什么会发生这种情况以及如何避免这种情况?

the*_*Man 6

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

\n

NodeSet文档text

\n
\n

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

\n
\n

这就是我们所看到的情况:

\n
doc = Nokogiri::HTML(<<EOT)\n<html>\n  <body>\n    <p>foo</p>\n    <p>bar</p>\n    <p>baz</p>\n  </body>\n</html>\nEOT\n\ndoc.search(\'p\').text # => "foobarbaz"\n
Run Code Online (Sandbox Code Playgroud)\n

因为:

\n
doc.search(\'p\').class # => Nokogiri::XML::NodeSet\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n
doc.search(\'p\').first.class # => Nokogiri::XML::Element\ndoc.search(\'p\').first.text # => "foo"\n
Run Code Online (Sandbox Code Playgroud)\n

可以使用以下方法完成map

\n
doc.search(\'p\').map { |node| node.text } # => ["foo", "bar", "baz"]\n
Run Code Online (Sandbox Code Playgroud)\n

Ruby 允许我们使用以下方式更简洁地编写:

\n
doc.search(\'p\').map(&:text) # => ["foo", "bar", "baz"]\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n

节点有几个别名方法来获取其嵌入的文本。从文档中中:

\n
\n

#content \xe2\x87\x92 Object

\n

也称为:text,inner_text

\n

返回此节点的内容。

\n
\n