[英]Why is XPath returning value of '0' using Ruby, Nokogiri and Watir?
我正在研究一個白帽網絡爬蟲,該爬蟲將定期登錄我的帳戶並使用Ruby和Watir和Nokogiri為我檢查一些信息。
這是我嘗試從中獲取信息的簡化HTML:
<div class="navbar navbar-default navbar-fixed-top hidden-lg hidden-md" style="z-index: 1002"> <div class="banner-g"> <div class="container"> <div id="user-info"> <div id="acct-value"> <a href="https://www.testsite.org/Profile/MyShares" title="Change in value of your shares">GAIN/LOSS <span class="SPShares">-$12.85</span></a> </div> <div id="committed"> <a href="https://www.testsite.org/Profile/MyShares" title="Amount paid for your shares">INVESTED <span class="SPPortfolio">$152.11</span></a> </div> <div id="avail"> <a href="https://www.testsite.org/Profile/MyShares">AVAILABLE <span class="SPBalance">$26.98</span></a> </div>
我試圖拉高$26.98.
在摘錄的底部。
這是我正在使用的三個代碼段。 除了XPath之外,它們幾乎完全相同。 前兩個完美地返回了它們的值,但是第三個始終返回值“ 0”,即使它“應該”返回“ $ 26.98”或“ 26.98”。
val_one = page_html.xpath(".//*[@id='openone']/div/div[2]/div[1]/div/div[2]/table/tbody/tr[2]/td[1]").text.gsub(/\D/,'').to_i
val_two = page_html.xpath(".//*[@id='opentwo']/div/div[2]/div[2]/div/div[2]/table/tbody/tr[2]/td[1]").text.gsub(/\D/,'').to_i
val_three = page_html.xpath(".//*[@id='avail']/a/span").text.gsub(/\D/,'').to_i
puts val_three
我認為這是XPath的問題,但是我在這里經歷了數十個XPath故障排除問題,但都沒有解決。 我同時使用FirePath和“ XPath Checker”檢查了XPath。 我還嘗試過XPath搜索“ SPBalance”類,但結果相同。
當我從最后刪除to.i
時,它返回一個空行而不是零。
使用Watir時,在網站的其他地方,我可以通過調用.focus
來解決記錄值的問題,但是對於這段代碼(更是Nokogiri),使用.focus
會導致錯誤消息:
undefined method `focus' for []:Nokogiri::XML::NodeSet (NoMethodError)
我認為.focus
對於Nokogiri不起作用。
更新:用更干凈/更完整的版本替換了HTML。
我繼續嘗試各種方法來訪問該數據單元,包括xpath,css和搜索方法。 有人告訴我xpath不適用於此頁面,所以我花了更多時間嘗試讓CSS工作。 有人告訴我頁面包含Javascript,這將阻止Watir工作。 因此,我嘗試改寫Selenium的應用程序。 硒不能解決問題,卻造成了許多其他問題。
更新:在聽了Tin Man的建議之后,我發現使用curl下載該節點時,該節點實際上在HTML中不可見。
我現在正嘗試使用Watir而非Nokogiri(如他的建議)來訪問節點。 這是到目前為止我嘗試過的一些方法:
avail_funds = browser.span :class => 'SPBalance'
avail_funds.exists?
avail_funds.text
avail_funds = browser.span(:css, 'span[customattribute]').text
avail_funds = browser.div(:id => "avail").a(:href => "/Profile/MyShares").span(:class => "SPBalance").text
avail_funds = browser.span(:xpath, ".//*[@id='avail']/a/span").text
avail_funds = browser.span(:css, 'span[class="SPBalance"]').text
avail_funds = browser.span.text
avail_funds = browser.div.text
browser.span(:class, "SPBalance").focus
avail_funds = browser.span(:class, "SPBalance").text
avail_funds = @browser.span(:class => 'SPBalance').inner_html
puts @browser.spans(:class => "SPBalance")
puts @browser.span(:class => "SPBalance")
texts = @browser.spans(:class => "SPBalance").map do |span|
span.text
end
到目前為止,以上所有內容都返回空行或錯誤消息。
通過curl下載時,在HTML中可見ID為“ user-info”的div類。 但是,下面的所有內容都不可見。
當我嘗試:
avail_funds = browser.div(:id => "user-info").text
我只有空白行。
當我嘗試:
avail_funds = browser.div(:class => "navbar navbar-default navbar-fixed-top hidden-xs hidden-sm").text
我得到了真實的文字! 但不幸的是,該字符串不包含我想要的值。
我也嘗試過:
puts browser.html
因為我認為該值在該版本的HTML中可見(例如通過Firefox插件可見),所以我可以解析為所需的值。 但不幸的是,該值在該版本的HTML中不可見。
通過前兩個命令,您可以從文檔的根目錄開始直接從表單元中獲取數據,而在最后一個命令中,您可以從中心開始獲取數據。
嘗試提供span ID並再次獲取數據,然后增加復雜度,您將在xpath中發現錯誤
第一個問題是您嘗試使用長而又長的選擇器來引用不存在的標記:
require 'nokogiri'
doc = Nokogiri::HTML(<<EOT)
<head>
<body class="cbp-spmenu-push">
<div id="FreshWidget" class="freshwidget-container responsive" data-html2canvas-ignore="true" style="display: none;">
<div id="freshwidget-button" class="freshwidget-button fd-btn-right" data-html2canvas-ignore="true" style="display: none; top: 235px;">
<link rel="stylesheet" href="/Content/css/NavPushComponent.css"/>
<script src="/Scripts/classie.js"/>
<script src="/Scripts/modernizr.custom.js"/>
<div class="navbar navbar-default navbar-fixed-top hidden-lg hidden-md" style="z-index: 1002">
<div class="banner-g">
<div class="container">
<div id="user-info">
<div id="acct-value">
<div id="committed">
<div id="avail">
<a href="/Profile/MyBalance">
AVAILABLE
<span class="SPBalance">$31.59</span>
EOT
doc.at('tbody') # => nil
".//*[@id='openone']/div/div[2]/div[1]/div/div[2]/table/tbody/tr[2]/td[1]" ".//*[@id='opentwo']/div/div[2]/div[2]/div/div[2]/table/tbody/tr[2]/td[1]"
您的示例中沒有<tbody>
標簽,並且很少在野外創建HTML,尤其是在人們手動創建的情況下。 我們通常會在HTML中看到<tbody>
,這是某人從瀏覽器的“查看源代碼”顯示中獲取的,這是他們的引擎修改HTML使其可讀之后的結果輸出。 不要使用該輸出。 取而代之的是, 始終直接使用源代碼,並使用wget
或curl
並下載頁面,然后使用編輯器對其進行檢查,甚至在命令行上使用nokogiri some_url
並在此處進行查看。
第二個問題是您的HTML代碼段無效,因為其中充滿了未終止的標記。 Nokogiri將對不良的HTML進行修復,這些HTML實際上可以移動節點,從而很難找到節點,尤其是在調試時。 在這種特殊情況下,Nokogiri可以終止它們,但是重要的是要遵守標簽的關閉要求。
這是我要用的:
value = doc.at('span.SPBalance').text # => "$31.59"
這是使用CSS的,它通常比XPath更易讀。 at
表示“查找第一個匹配項”,等效於search('span.SPBalance').first
。
等效的XPath為:
doc.at('//span[@class="SPBalance"]')
doc.at('//span[@class="SPBalance"]').text # => "$31.59"
一旦有了價值,就很容易操縱它。
value[/[\d.]+/].to_f # => 31.59
繼續...
第三個總是返回值“ 0”,即使它應返回“ $ 31.59”或“ 31.59”
'$31.58'.to_i # => 0
'$'.to_i # => 0
'31.58'.to_i # => 31
'$31.58'.to_f # => 0.0
'31.58'.to_f # => 31.58
返回將str中的前導字符解釋為浮點數的結果。
和
返回將str中的前導字符解釋為整數基數(2到36之間)的結果。
在這兩種情況下,“主角”都是重要的。
使用.focus會導致錯誤消息:
undefined method `focus' for []:Nokogiri::XML::NodeSet (NoMethodError)
我認為.focus對於Nokogiri不起作用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.