nil:NilClass 的未定义方法“attr”(NoMethodError)
undefined method `attr' for nil:NilClass (NoMethodError)
我的 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
,但没有帮助。另外,我不是每次都收到这个错误,但我想摆脱它。
正如您的堆栈跟踪显示此行导致错误:
@purchase_link= doc.at_css("div.detailLeftColumn a.success").attr("href")
attr
方法不能在 nil 上调用。查看元素是否存在于 HTML 中。
您可以通过打印
的值来调试它
doc.at_css("div.detailLeftColumn a.success")
解决这个问题的一种方法是有点偏执:
@purchase_link = doc.at_css("div.detailLeftColumn a.success").try(:attr, "href")
deal[:purchase] = @purchase_link || @product_url
这里有几件事要记住。在 Ruby 只有 nil
和 false
逻辑上是错误的,所以很少需要专门测试 nil?
的东西。唯一需要的情况是当您想区分 nil
和 false
时,您可以想象这种情况并不常见。
所以在这种情况下,要么你用 at_css
命中某些东西,要么你没有,在这种情况下 try
调用不会做任何事情。如果它发现某些东西,try
调用会继续进行另一个调用。然后,您可以使用简单的 ||
(或)运算符进行赋值,以优先选择它们。
还有就是这段代码是在class方法里面,随便用实例变量会很麻烦。如果 purchase_link
之类的东西仅在此方法中使用,请删除使它们持久化的 @
。
另一件要注意的事情是你的方法是如何定义的:
def self.deal_page(input, product_url)
那声明了一个参数product_url
,但是里面:
html = open(@product_url)
这引用了不相同的 class 实例变量 @product_url
。您可能在此处使用错误的变量调用 open
。
我认为问题出在这里:
def self.deal_page(input, product_url)
...
html = open(@product_url)
您正在使用 product_url
作为参数,但试图打开 @product_url
。
如果 @product_url
为空或 nil,open
将引发错误,因此 @product_url
必须预定义 某处 ,但显然不在这个方法。我怀疑这不是您认为的页面,因此选择器失败了。
您的代码还有其他问题:
deal[:name] = doc.css("h1").text.strip
deal[:discription] = doc.css(".textDescription").text.strip
您正在使用 css
,其中 returns 一个 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)
,除非在 罕见的 情况下您知道文本实际上需要连接起来。我只 运行 遇到过这种情况......哦......从来没有过。
我的 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
,但没有帮助。另外,我不是每次都收到这个错误,但我想摆脱它。
正如您的堆栈跟踪显示此行导致错误:
@purchase_link= doc.at_css("div.detailLeftColumn a.success").attr("href")
attr
方法不能在 nil 上调用。查看元素是否存在于 HTML 中。
您可以通过打印
的值来调试它doc.at_css("div.detailLeftColumn a.success")
解决这个问题的一种方法是有点偏执:
@purchase_link = doc.at_css("div.detailLeftColumn a.success").try(:attr, "href")
deal[:purchase] = @purchase_link || @product_url
这里有几件事要记住。在 Ruby 只有 nil
和 false
逻辑上是错误的,所以很少需要专门测试 nil?
的东西。唯一需要的情况是当您想区分 nil
和 false
时,您可以想象这种情况并不常见。
所以在这种情况下,要么你用 at_css
命中某些东西,要么你没有,在这种情况下 try
调用不会做任何事情。如果它发现某些东西,try
调用会继续进行另一个调用。然后,您可以使用简单的 ||
(或)运算符进行赋值,以优先选择它们。
还有就是这段代码是在class方法里面,随便用实例变量会很麻烦。如果 purchase_link
之类的东西仅在此方法中使用,请删除使它们持久化的 @
。
另一件要注意的事情是你的方法是如何定义的:
def self.deal_page(input, product_url)
那声明了一个参数product_url
,但是里面:
html = open(@product_url)
这引用了不相同的 class 实例变量 @product_url
。您可能在此处使用错误的变量调用 open
。
我认为问题出在这里:
def self.deal_page(input, product_url)
...
html = open(@product_url)
您正在使用 product_url
作为参数,但试图打开 @product_url
。
@product_url
为空或 nil,open
将引发错误,因此 @product_url
必须预定义 某处 ,但显然不在这个方法。我怀疑这不是您认为的页面,因此选择器失败了。
您的代码还有其他问题:
deal[:name] = doc.css("h1").text.strip
deal[:discription] = doc.css(".textDescription").text.strip
您正在使用 css
,其中 returns 一个 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)
,除非在 罕见的 情况下您知道文本实际上需要连接起来。我只 运行 遇到过这种情况......哦......从来没有过。