未定义的方法`attr' for nil:NilClass(NoMethodError)

时间:2017-04-06 16:28:53

标签: css ruby nokogiri open-uri

我的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,但没有帮助。此外,我不是每次都会收到此错误,但我想摆脱它。

3 个答案:

答案 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),但稀有情况除外,您知道文本实际上需要连接。我只是碰到那种情况......哦......从来没有。