2014-12-04 73 views
3

我试图从使用Nokogiri的HTML文档中获取所有节点。如果你们认为它更容易,我可以使用其他的东西。使用Nokogiri从Ruby中的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" ] 

我不需要结束标记。

有没有人有更好的解决方案来实现这个目标?

+0

你为什么这样做?迭代遍历每个节点是非常低效的。你可以用SAX解析器做同样的事情,它可能运行得更快。 – 2014-12-04 16:17:53

回答

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”。

+0

谢谢田满。简直不敢相信你的解决方案!我知道如何迭代节点,但我需要所有这些节点,并不知道'*'。我需要保存所有节点,因为我想比较两个不同网站的结构。我最终使用了一个更长的示例HTML,以确保我有足够的嵌套层次并证明订单的重要性。 – radubogdan 2014-12-04 21:13:35