2016-04-28 47 views
1

我試圖刮掉,並從該HTML CSV文件:如何HTML數據導出爲CSV文件

<ul class="object-props"> 
       <li class="object-props-item price"> 
        <strong>CHF 14&#39;800.-</strong> 
       </li> 
       <li class="object-props-item milage">31&#39;000 km</li> 
       <li class="object-props-item date">08.2012</li> 
      </ul> 

我想用提取的價格和里程:

require 'rubygems' 
require 'nokogiri' 
require 'CSV' 
require 'open-uri' 

url= "/tto.htm" 
data = Nokogiri::HTML(open(url)) 

CSV.open('csv.csv', 'wb') do |csv| 
    csv << %w[ price mileage ] 

    price=data.css('.price').text 
    mileage=data.css('.mileage').text 

    csv << [price, mileage] 
end 

結果並不是我所期待的。創建了兩列,但如何刪除CHF和KM等字符,以及爲什麼不顯示里程數據result

+0

我不認爲這是你的問題的原因,但你打開文件以二進制模式寫入('wb')。 CSV是一個文本表示,所以我很確定你應該以文本模式('w')打開它。 –

+0

當詢問您的代碼有問題時,我們需要看到您嘗試解決問題。在您的代碼中,您不會顯示您試圖刪除CHF和KM數據的位置;請補充一點。沒有它,看起來你問我們如何編寫你的代碼,這不是它的目的。此外,你的「結果」不應該是一個圖像的鏈接。相反,請在問題本身中提供這些信息。 「[mcve]」描述我們需要的東西。要刪除這些信息,使用檢索到的文本上的'delete'或'sub'或更好的方法,使用'tr'來刪除你不想要的東西,或者寫一個正則表達式來只提取你想要的東西。 –

+0

此外,您的輸入HTML無效。爲了解釋爲什麼這很重要,請參閱我的答案。 –

回答

0

我的猜測是HTML中的文本包含度量單位;瑞士法郎爲CHF,里程爲公里數km

您可以添加split.firstsplit.last獲得數量,而不度量單位,如:

2.3.0 :007 > 'CHF 100'.split.last 
=> "100" 
2.3.0 :008 > '99 km'.split.first 
=> "99" 
+0

好吧,想你爲tipp,但是當我申請時,我想我錯過了一些東西,因爲:'price.split.last'只返回我的.csv中的第一個值。Anyway感謝快速響應,我沒有想到這樣反應性 –

+0

請說明你做了什麼以及結果是什麼。 –

+0

'price = data.css('。price').text''和'price = price.split.last'爲了適用您的建議。 –

0

刪除/忽略不需要的文本是不是一個引入nokogiri問題,這是一個字符串處理的問題:

require 'nokogiri' 

doc = Nokogiri::HTML(<<EOT) 
li class="object-props-item price" 
<strong>CHF 14&#39;900.-</strong> 
<li class="object-props-item milage">61&#39;000 km</li> 
EOT 

str = doc.at('strong').text # => "CHF 14'900.-" 

此時str包含<strong>節點的文本。

一個簡單的正則表達式將提取,這是爲了獲取數據的直接方式:

str[/[\d']+/] # => "14'900" 

sub可以用來除去'CHF '子:

str.sub('CHF ', '') # => "14'900.-" 

delete可用於除去字符C,H,F

str.delete('CHF ') # => "14'900.-" 

tr可以用來去除一切不是0 .. 9'.-

str.tr("^0-9'.-", '') # => "14'900.-" 

修改上面的一個,如果你不想'.-做。

爲什麼的里程不顯示

的數據,因爲你的CSS選擇器和實際class參數之間的不匹配:

require 'nokogiri' 

doc = Nokogiri::HTML('<li class="object-props-item milage">61&#39;000 km</li>') 

doc.at('.mileage').text # => 
# ~> NoMethodError 
# ~> undefined method `text' for nil:NilClass 
# ~> 
# ~> /var/folders/yb/whn8dwns6rl92jswry5cz87dsgk2n1/T/seeing_is_believing_temp_dir20160428-96035-1dajnql/program.rb:5:in `<main>' 

相反,它應該是:

doc.css('.milage').text # => "61'000 km" 

但這並不全是錯的。有一個微妙的問題等待你咬你。

csssearch返回一個節點集而atat_css返回一個元素:

doc.css('.milage').class # => Nokogiri::XML::NodeSet 
doc.at('.milage').class # => Nokogiri::XML::Element 

下面是當text傳遞包含多個匹配的節點一個節點集會發生什麼:

doc = Nokogiri::HTML('<p>foo</p><p>bar</p>') 

doc.search('p').class # => Nokogiri::XML::NodeSet 
doc.search('p').text # => "foobar" 

doc.at('p').class # => Nokogiri::XML::Element 
doc.at('p').text # => "foo" 

當使用text使用NodeSet,它將所有節點的文本連接成單個字符串。這可能會使文本從一個節點與另一個節點分離變得非常困難。相反,使用at或其中一個at_*等價物可從單個節點獲取文本。如果你想單獨提取每個節點的文本,並得到一個陣列中使用:

doc.search('p').map(&:text) # => ["foo", "bar"] 

見「How to avoid joining all text from Nodes when scraping」也。

最後,注意你的HTML示例是無效的:

doc = Nokogiri::HTML(<<EOT) 
li class="object-props-item price" 
<strong>CHF 14&#39;900.-</strong> 
<li class="object-props-item milage">61&#39;000 km</li>') 
EOT 

puts doc.to_html 

# >> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"> 
# >> <html><body> 
# >> <p>li class="object-props-item price" 
# >> <strong>CHF 14'900.-</strong> 
# >> </p> 
# >> <li class="object-props-item milage">61'000 km</li>') 
# >> </body></html> 

這裏發生了什麼:

doc = Nokogiri::HTML(<<EOT) 
li class="object-props-item price" 
<strong>CHF 14&#39;900.-</strong> 
<li class="object-props-item milage">61&#39;000 km</li>') 
EOT 

doc.at('.price') # => nil 

引入nokogiri已經做了修復行動,使第一線的感覺,所以它包裝在<p>。通過這樣做,.price類不再存在,因此您的代碼將再次失敗。

固定的標籤結果的正確響應:

doc = Nokogiri::HTML(<<EOT) 
<li class="object-props-item price"> 
<strong>CHF 14&#39;900.-</strong> 
</li> 
<li class="object-props-item milage">61&#39;000 km</li>') 
EOT 
doc.at('.price').to_html # => "<li class=\"object-props-item price\">\n<strong>CHF 14'900.-</strong>\n</li>" 

這就是爲什麼它,以確保您的輸入有效真的很重要。沒有它,試圖複製你的問題是困難的。

+0

我改變了我的輸入,但是我不能把所有的代碼都放在這裏,因爲太大了,請您幫忙 –

+0

我們並不想要你所有的代碼。 「[mcve]」說你應該使用必要的最小代碼和輸入來證明問題。 「[問]」底部的鏈接解釋了這些要求背後的推理,這些要求基本上是在問這裏之前教授調試。通常,在這樣做之後,人們不需要問就能找到解決問題的辦法。 –