【问题标题】:How to get all nodes from a HTML document in Ruby with Nokogiri如何使用 Nokogiri 从 Ruby 中的 HTML 文档中获取所有节点
【发布时间】:2015-02-02 13:55:25
【问题描述】:

我正在尝试使用 Nokogiri 从 HTML 文档中获取所有节点。

我有这个 HTML:

<html>
<body>
  <h1>Header1</h1>
  <h2>Header22</h2>
  <ul>
    <li>Li1</li>
    <ul>
       <li>Li1</li>
       <li>Li2</li>
    </ul>
  </ul>
</body>
</html>

字符串版本:

string_page = "<html><body><h1>Header1</h1><h2>Header22</h2><ul><li>Li1</li><ul><li>Li1</li><li>Li2</li></ul></ul></body></html>"

我创建了一个对象:

page = Nokogiri.HTML(string_page)

我试图遍历它:

result = []
page.traverse { |node| result << node.name unless node.name == "text" }
=> ["html", "h1", "h2", "li", "li", "li", "ul", "ul", "body", "html", "document"]

但我不喜欢的是元素的顺序。我需要一个与它们出现的顺序相同的数组:

["html", "body", "h1", "h2", "ul", "li", "ul", "li", "li" ]

我不需要结束标签。

有没有人有更好的解决方案来做到这一点?

【问题讨论】:

  • 你为什么要这么做?通过迭代遍历每个节点是非常低效的。您可以使用 SAX 解析器做同样的事情,而且它可能会运行得更快。

标签: ruby nokogiri


【解决方案1】:

如果您想按顺序查看节点,请使用像 '*' 这样的 XPath 选择器,这意味着“一切”,从根节点开始:

require 'nokogiri'
string_page = "<html><body><h1>Header1</h1></body></html>"
doc = Nokogiri::HTML(string_page)
doc.search('*').map(&:name)
# => ["html", "body", "h1"]

但是,我们通常不关心迭代每个节点,我们通常也不想这样做。我们想找到某种类型的所有节点或单个节点,因此我们在标记中寻找地标并从那里开始:

doc.at('h1').text # => "Header1"

或:

html = "<html><body><table><tr><td>cell1</td></tr><tr><td>cell2</td></tr></h1></body></html>"
doc = Nokogiri::HTML(html)
doc.search('table tr td').map(&:text) # => ["cell1", "cell2"]

或:

doc.search('tr td').map(&:text) # => ["cell1", "cell2"]

或:

doc.search('td').map(&:text) # => ["cell1", "cell2"]

注意:没有理由使用更长的示例 HTML 字符串;它只会使问题变得混乱,因此请使用一个最小的示例。

另见“How to avoid joining all text from Nodes when scraping”。

【讨论】:

  • 谢谢铁皮人。不敢相信你的解决方案这么简单!我知道如何迭代节点,但我需要所有节点并且不知道*。我需要保存所有节点,因为我想比较两个不同网站的结构。我最终使用了更长的示例 HTML 来确保我有足够的嵌套级别并证明顺序的重要性。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-30
  • 1970-01-01
  • 2018-05-03
  • 2013-11-22
  • 2021-12-20
相关资源
最近更新 更多