はい、そのエラーは、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つの表があります。 「衝突率/検査」テーブルはどれですか?あなたのURLに最後に#Inspections
が含まれているとすれば、私はあなたが「Inspections/Crashes In US」セクションのすぐ下の2つのテーブルについて話していると仮定しています。それぞれに一致する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クエリは恐ろしく見えるかもしれません。私は、彼らがどのように動作するかを説明しましょう:
//table[@summary="Inspections"][preceding::h4[.//a[@name="Inspections"]]]
//table
文書
[@summary="Inspections"]
の任意のレベルで<table>
を見つける...それはこれでsummary
属性を持つ場合にのみ、値
[preceding::h4…]
...とだけあなたが<h4>
要素以前の文書
[.//a…]
で見つけることができるかどうか...どこか
[@name="Inspections"]
...と<a>
はname
を有していなければならないことの下<a>
があり、特に、<h4>
このテキストの属性。
これは実際には2つのテーブルを(別のsummary="Inspections"
表がページに後であります)と一致しますが、at_xpath
を使用すると、最初に一致したテーブルを見つけます。現在のノード(この表)
//tr[2]
で開始
.//tr[2]/td
.
...任意のレベル
/td
に子孫である<tr>
秒を見つける...とその子供の<td>
が見つかりました。
また、at_xpath
を使用しているため、最初の一致は<td>
です。現在のノード(この表)
//tr
で開始
.//tr[th="Out of Service"]/td[2]
.
...任意のレベル
[th="Out of Service]
に子孫である任意<tr>
を見つける...しかし<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]
。誰かがページに新しいセクションを追加したり、フォーマットテーブルを追加または削除したりするコードでは、それらの式が壊れてしまいます。おそらく変化しない強力な属性やテキストを探して、それに基づいて検索を固定したいとします。
vehicle_inspections
XPathも同様に脆弱で、行のラベルテキストではなく行の順序に依存します。
問題を示すサンプルHTMLを追加してください。 URLが指すページが消えてしまった場合、あなたの質問は将来問題が発生した人には本当に役立つものではありません。 –