2011-06-04 65 views
5

我想用Nokogiri解析HTML頁面。頁面的一部分沒有使用任何特定的ID。是否可以提取類似:如何用Nokogiri解析純HTML表格?

Today,3,455,34 
Today,1,1300,3664 
Today,10,100000,3444, 
Yesterday,3454,5656,3 
Yesterday,3545,1000,10 
Yesterday,3411,36223,15 

從這個HTML:

<div id="__DailyStat__"> 
    <table> 
    <tr class="blh"><th colspan="3">Today</th><th class="r" colspan="3">Yesterday</th></tr> 
    <tr class="blh"><th>Qnty</th><th>Size</th><th>Length</th><th class="r">Length</th><th class="r">Size</th><th class="r">Qnty</th></tr> 
    <tr class="blr"> 
     <td>3</td> 
     <td>455</td> 
     <td>34</td> 
     <td class="r">3454</td> 
     <td class="r">5656</td> 
     <td class="r">3</td> 
    </tr> 

    <tr class="bla"> 
     <td>1</td> 
     <td>1300</td> 
     <td>3664</td> 
     <td class="r">3545</td> 
     <td class="r">1000</td> 
     <td class="r">10</td> 
    </tr> 

    <tr class="blr"> 
     <td>10</td> 
     <td>100000</td> 
     <td>3444</td> 
     <td class="r">3411</td> 
     <td class="r">36223</td> 
     <td class="r">15</td> 
    </tr> 
    </table> 
</div> 

回答

9

作爲一個快速和骯髒的第一遍我會怎麼做:

html = <<EOT 
<div id="__DailyStat__"> 
    <table> 
    <tr class="blh"><th colspan="3">Today</th><th class="r" colspan="3">Yesterday</th></tr> 
    <tr class="blh"><th>Qnty</th><th>Size</th><th>Length</th><th class="r">Length</th><th class="r">Size</th><th class="r">Qnty</th></tr> 
    <tr class="blr"> 
     <td>3</td> 
     <td>455</td> 
     <td>34</td> 
     <td class="r">3454</td> 
     <td class="r">5656</td> 
     <td class="r">3</td> 
    </tr> 

    <tr class="bla"> 
     <td>1</td> 
     <td>1300</td> 
     <td>3664</td> 
     <td class="r">3545</td> 
     <td class="r">1000</td> 
     <td class="r">10</td> 
    </tr> 

    <tr class="blr"> 
     <td>10</td> 
     <td>100000</td> 
     <td>3444</td> 
     <td class="r">3411</td> 
     <td class="r">36223</td> 
     <td class="r">15</td> 
    </tr> 
    </table> 
</div> 
EOT 

# Today    Yesterday 
# Qnty Size Length Length Size Qnty 
# 3 455 34  3454 5656 3 
# 1 1300 3664 3545 1000 10 
# 10 100000 3444 3411 36223 15 


require 'nokogiri' 

doc = Nokogiri::HTML(html) 

使用CSS找到表格的開始,並定義一些地方以容納我們正在捕獲的數據:

table = doc.at('div#__DailyStat__ table') 

today_data  = [] 
yesterday_data = [] 

遍歷在表中的行,拒絕該標頭:

table.search('tr').each do |tr| 

    next if (tr['class'] == 'blh') 

初始化陣列以從每個行捕捉相關數據,選擇性地將數據推入相應的數組:

today_td_data  = [ 'Today'  ] 
    yesterday_td_data = [ 'Yesterday' ] 

    tr.search('td').each do |td| 
    if (td['class'] == 'r') 
     yesterday_td_data << td.text.to_i 
    else 
     today_td_data << td.text.to_i 
    end 
    end 

    today_data  << today_td_data 
    yesterday_data << yesterday_td_data 

end 

而輸出數據:

puts today_data.map{ |a| a.join(',') } 
puts yesterday_data.map{ |a| a.join(',') } 

> Today,3,455,34 
> Today,1,1300,3664 
> Today,10,100000,3444 
> Yesterday,3454,5656,3 
> Yesterday,3545,1000,10 
> Yesterday,3411,36223,15 

只是爲了幫助您可視發生了什麼事情,在出口處從「TR」循環中,陣列陣列的-3210個yesterday_data陣列看起來像:

[["Today", 3, 455, 34], ["Today", 1, 1300, 3664], ["Today", 10, 100000, 3444]] 

另一方面,不是循環在「TD」標籤和感應的標籤類,我可以抓住的「TR」的內容然後用scan搶號和切片結果數組到「今天」和「昨天」陣列:

tr_data = tr.text.scan(/\d+/).map{ |i| i.to_i } 

    today_td_data  = [ 'Today',  *tr_data[0, 3] ] 
    yesterday_td_data = [ 'Yesterday', *tr_data[3, 3] ] 

在現實世界中的發展,如在工作中,我第一次用這個來代替我因爲它很簡潔而寫了。

並注意到我沒有使用XPath。在Nokogiri中使用XPath並實現這一點非常實用,但爲了簡單起見,我更喜歡CSS訪問器。 XPath允許訪問單獨的「td」標籤內容,但它也開始看起來像線噪聲,這是我們在編寫代碼時要避免的,因爲它會影響維護。我也可以使用CSS深入到正確的「td」標籤,如'tr td.r',但我認爲它不會改進代碼,它只是一種替代方法。

+0

謝謝@錫人。它工作正常,只是因爲得到一些錯誤,我必須將doc.at更改爲doc.css。我有一些小問題,我會盡力解決。我沒有足夠的聲望來投票,所以振作起來:) – JraNil 2011-06-04 20:28:21

+0

'at'與CSS和XPath一起工作,但只返回節點的第一次出現,所以您可能有多個'table'標記。 'css'是'search'的別名,它返回一個NodeSet,AKA是一個節點數組,所以你必須索引結果或迭代它們。 'at_css'是與'at'等效的CSS。 – 2011-06-04 20:32:34

+0

@JraNil此外,作爲參考,代碼與您的示例HTML一起工作,因此示例中必須缺少某些內容。如果您生成準確的樣本,我們可以提供更好的答案。 – 2011-06-04 20:39:48