我的CLI应用程序中有一个方法,它给了我一个错误。
方法是:
def self.deal_page(input, product_url)
self.open_deal_page(input)
deal = {}
html = open(@product_url)
doc = Nokogiri::HTML(html)
data = doc.text.strip
deal[:name] = doc.css("h1").text.strip
deal[:discription] = doc.css(".textDescription").text.strip
@purchase_link = nil
@purchase_link= doc.at_css("div.detailLeftColumn a.success").attr("href")
if @purchase_link.nil?
deal[:purchase] = @product_url
else
deal[:purchase] = @purchase_link
end
deal
end
,错误是:
/home/himachhag-45739/code/popular-deals-from-slickdeals.net-cli/lib/popular_deals/newdeals.rb:54:in `deal_page': undefined method `attr' for nil:NilClass (NoMethodError)
from /home/himachhag-45739/code/popular-deals-from-slickdeals.net-cli/lib/popular_deals/cli.rb:70:in `disply_deal'
from /home/himachhag-45739/code/popular-deals-from-slickdeals.net-cli/lib/popular_deals/cli.rb:49:in `menu'
from /home/himachhag-45739/code/popular-deals-from-slickdeals.net-cli/lib/popular_deals/cli.rb:9:in `call'
from /home/himachhag-45739/code/popular-deals-from-slickdeals.net-cli/bin/popular-deals:10:in `<top (required)>'
from /usr/local/rvm/gems/ruby-2.3.1/bin/popular-deals:22:in `load'
from /usr/local/rvm/gems/ruby-2.3.1/bin/popular-deals:22:in `<main>'
from /usr/local/rvm/gems/ruby-2.3.1/bin/ruby_executable_hooks:15:in `eval'
from /usr/local/rvm/gems/ruby-2.3.1/bin/ruby_executable_hooks:15:in `<main>'
我尝试了xpath
,at_css
,unless
,if
.. else
,但没有帮助。此外,我不是每次都会收到此错误,但我想摆脱它。
答案 0 :(得分:4)
One way to address this problem is to be a bit paranoid:
@purchase_link = doc.at_css("div.detailLeftColumn a.success").try(:attr, "href")
deal[:purchase] = @purchase_link || @product_url
A couple of things to keep in mind here. In Ruby only nil
and false
are logically false, so it's very rare you need to specifically test nil?
on things. The only case that's necessary is when you want to distinguish between nil
and false
, which as you can imagine is not very often.
So in this case either you hit something with at_css
or you didn't, in which case the try
call doesn't do anything. If it finds something the try
call carries on for one more call. Then you can do an assignment with a simple ||
(or) operator to pick them in priority.
Another thing is since this code is inside a class method, casually using instance variables can be trouble. If things like purchase_link
are only used within this method, remove the @
which makes them persistent.
Another thing to be careful about is how your method is defined as:
def self.deal_page(input, product_url)
That declares an argument product_url
, but inside:
html = open(@product_url)
This references the class instance variable @product_url
which is not the same. You may be calling open
with the wrong variable here.
答案 1 :(得分:0)
As your stack trace shows this line is causing the error:
@purchase_link= doc.at_css("div.detailLeftColumn a.success").attr("href")
attr
method can not be called on nil. See if the element exists in the HTML.
You can debug this by printing the value of
doc.at_css("div.detailLeftColumn a.success")
For more information you can refer to http://www.nokogiri.org/tutorials/.
答案 2 :(得分:0)
我认为问题在于:
def self.deal_page(input, product_url)
...
html = open(@product_url)
您使用product_url
作为参数,但尝试打开@product_url
。
open
为空或为零,则 @product_url
会引发错误,因此@product_url
必须预定义某处,但显然不在此方法中。我怀疑它不是您认为的页面,因此选择器失败了。
您的代码中还有其他问题:
deal[:name] = doc.css("h1").text.strip
deal[:discription] = doc.css(".textDescription").text.strip
您正在使用css
,它返回一个NodeSet
doc.css('h1').class # => Nokogiri::XML::NodeSet
然后text
连接NodeSet中的所有文本,这几乎总是不你想要做什么。考虑一下:
require 'nokogiri'
doc = Nokogiri::HTML(DATA.read)
doc.css('h1').text # => "foobar"
doc.css('h1').map(&:text) # => ["foo", "bar"]
__END__
<html>
<body>
<h1>foo</h1>
<h2>blah</h2>
<h1>bar</h1>
<h2>blah</h2>
</body>
</html>
doc.css('h1').text
连结"foo"
和"bar"
,结果为"foobar"
。一旦你发生了这种情况,就很难解开由连接引起的混乱。
相反,您应该使用doc.css('h1').map(&:text)
,但稀有情况除外,您知道文本实际上需要连接。我只是碰到那种情况......哦......从来没有。