2011-12-06 149 views
2

我正在使用Nokogiri刮一個網站,當我嘗試從表格中抓取一個字段時遇到問題。我正在使用selector gadget來查找表格的CSS選擇器。我從government website that details information on motor carriers獲取數據。用Nokogiri刮一個網站

的方法,我使用看起來像:

def scrape_database 
    url = "http://safer.fmcsa.dot.gov/query.asp?searchtype=ANY&query_type=queryCarrierSnapshot&query_param=USDOT&query_string=#{self.dot}#Inspections" 
    doc = Nokogiri::HTML(open(url)) 
    self.name = doc.at_css("tr:nth-child(4) .queryfield").text 
    self.address = doc.at_css("tr:nth-child(6) .queryfield").text 
end 

我抓住所有在上表中的字段使用語法和方法工作正常,但是我有碰撞率/檢查問題它下面的表格。

這裏是我使用的搶信息的內容:

self.vehicle_inspections = doc.at_css("center:nth-child(13) tr:nth-child(2) :nth-child(2)").text 

undefined method `text' for nil:NilClass 

如果我從這個月底,方法運行刪除text,但不會搶任何相關信息(明顯)。我假設這是由於我用來搶場的複雜選擇器,但我不太確定。

有沒有人遇到類似的問題,你能給我一些建議嗎?

+0

請添加一些示例HTML顯示問題。如果URL指向的頁面將消失,您的問題將不會真正幫助任何人在將來遇到問題。 –

回答

4

是的,那個錯誤意味着你的CSS選擇器沒有找到信息; at_css正在返回nil,並且nil.text無效。你可以這樣防範:

insp = doc.at_css("long example css selector") 
self.vehicle_inspections = insp && insp.text 

但是,這聽起來像你「需要」這些數據。既然你沒有提供HTML頁面和CSS選擇器,我無法幫你製作一個可用的CSS或XPath選擇器。

對於將來的問題,或對其進行編輯,請注意,實際(減量)代碼比手動揮手和寬鬆描述您的代碼的外觀更強烈。如果您向我們展示HTML頁面或相關代碼段,並描述您想要的元素/文本/屬性,我們可以告訴您如何選擇它。

更新:我在該頁面上看到6個表格。哪個是「碰撞率/檢查」表?鑑於您的網址最終包含#Inspections,我假設您正在討論「Inspections/Crashes In US」部分下方的兩個表格。以下是匹配的XPath選擇器:

require 'nokogiri' 
require 'open-uri' 

url = "http://safer.fmcsa.dot.gov/query.asp?searchtype=ANY&query_type=queryCarrierSnapshot&query_param=USDOT&query_string=800585" 
doc = Nokogiri::HTML(open(url)) 
table1 = doc.at_xpath('//table[@summary="Inspections"][preceding::h4[.//a[@name="Inspections"]]]') 
table2 = doc.at_xpath('//table[@summary="Crashes"][preceding::h4[.//a[@name="Inspections"]]]') 

# Find a row by index (1 is the first row) 
vehicle_inspections = table1.at_xpath('.//tr[2]/td').text.to_i 

# Find a row by header text 
out_of_service_drivers = table1.at_xpath('.//tr[th="Out of Service"]/td[2]').text.to_i 

p [ vehicle_inspections, out_of_service_drivers ] 
#=> [6, 0] 

tow_crashes = table2.at_xpath('.//tr[th="Crashes"]/td[3]').text.to_i 
p tow_crashes 
#=> 0 

XPath查詢可能看起來很嚇人。讓我來解釋他們是如何工作的:

  1. //table[@summary="Inspections"][preceding::h4[.//a[@name="Inspections"]]]

    • //table在文檔
    • [@summary="Inspections"]的任何級別找到<table> ......但只有當它有一個summary屬性與此值
    • [preceding::h4…] ......只有當你能更早的文檔中找到一個<h4>元素
    • [.//a…] ...具體地說,<h4>有一個<a>某處它的下面
      • [@name="Inspections"] ...這<a>必須有一個name屬性與此文本。

    這實際上匹配兩個表(還有另一個summary="Inspections"表後面的頁面上),但使用at_xpath找到的第一個匹配表。

  2. .//tr[2]/td

    • .在當前節點開始(此表)
    • //tr[2] ...找到第二<tr>即在任何級別
    • /td後代......和然後找到那個<td>的孩子。

    同樣,因爲我們使用的是at_xpath,所以我們找到第一個匹配的<td>

  3. .//tr[th="Out of Service"]/td[2]

    • .在當前節點開始(此表)
    • //tr ...找到任何<tr>即在任何級別
      • [th="Out of Service]後代......但只有那些<tr>有一個<th>孩子本文
    • /td[2] ...然後找到那些第二<td>孩子。

    在這種情況下,只有一個<tr>符合條件,因而僅匹配一個<td>,但我們仍然使用at_xpath,使我們得到了節點,而不是直接在一個單一元素的節點集。

這裏(和任何屏幕抓取)的目標是鎖定頁面上的有意義的值,而不是任意索引。

例如,我可以寫我的table1的XPath爲:

# Find the first table with this summary 
table1 = doc.at_xpath('//table[@summary="Inspections"][1]') 

...甚至...

# Find the 20th table on the page 
//table[20] 

然而,這些都是脆弱。有人在頁面上添加新節,或者添加或移除格式表的代碼會導致這些表達式中斷。您想要搜索可能不會更改的強屬性和文本,並根據該文字進行搜索。

0123pXPath同樣很脆弱,依賴於行的排序而不是行的標籤文本。

+0

確定這裏是我試圖抓取信息的示例頁面:[更安全](http://safer.fmcsa.dot.gov/query.asp?searchtype=ANY&query_type=queryCarrierSnapshot&query_param=USDOT&query_string=800789)有兩個主要我正在查看的數據表,它的個人數據和檢查/崩潰表。我將更新上面的選擇器以顯示我正在使用什麼不工作。 – tomciopp

+0

@ demondeac11很好,這有幫助。我已經編輯了我的答案,以獲得我想要的*想要的內容,解釋了XPath的工作原理,以便您可以製作自己的查詢,並試圖描述爲什麼使用基於索引的CSS選擇器太脆弱。 – Phrogz

+0

@Phrogz +1謝謝,你的解釋幫了我很多 – Hishalv