2014-12-04 111 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