簡體   English   中英

為什么XPath使用Ruby,Nokogiri和Watir返回值“ 0”?

[英]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使其可讀之后的結果輸出。 不要使用該輸出。 取而代之的是, 始終直接使用源代碼,並使用wgetcurl並下載頁面,然后使用編輯器對其進行檢查,甚至在命令行上使用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

to_fto_i的文檔分別說:

返回將str中的前導字符解釋為浮點數的結果。

返回將str中的前導字符解釋為整數基數(2到36之間)的結果。

在這兩種情況下,“主角”都是重要的。


使用.focus會導致錯誤消息:

  undefined method `focus' for []:Nokogiri::XML::NodeSet (NoMethodError) 

我認為.focus對於Nokogiri不起作用。

您始終可以查看NodeSet文檔 ,該文檔確認focus不是方法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM