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>'

我尝试了 xpathat_cssunlessif..else,但没有帮助。另外,我不是每次都收到这个错误,但我想摆脱它。

正如您的堆栈跟踪显示此行导致错误:

@purchase_link= doc.at_css("div.detailLeftColumn a.success").attr("href")

attr 方法不能在 nil 上调用。查看元素是否存在于 HTML 中。

您可以通过打印

的值来调试它
doc.at_css("div.detailLeftColumn a.success")

更多信息请参考http://www.nokogiri.org/tutorials/

解决这个问题的一种方法是有点偏执:

@purchase_link = doc.at_css("div.detailLeftColumn a.success").try(:attr, "href")

deal[:purchase] = @purchase_link || @product_url

这里有几件事要记住。在 Ruby 只有 nilfalse 逻辑上是错误的,所以很少需要专门测试 nil? 的东西。唯一需要的情况是当您想区分 nilfalse 时,您可以想象这种情况并不常见。

所以在这种情况下,要么你用 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),除非在 罕见的 情况下您知道文本实际上需要连接起来。我只 运行 遇到过这种情况......哦......从来没有过。