2017-04-06 91 views
1

我有一个方法在我的CLI应用程序中给我一个错误。未定义的方法`attr'为零:NilClass(NoMethodError)

的方法是:

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,但于事无补。另外,我不会每次都得到这个错误,但我想摆脱它。

+1

当遇到像这样的'nil'问题时,退一步操作并查看未能参与的操作非常重要。它看起来像'doc.at_css(...)'没有找到任何东西。另外需要注意的是试着保持缩进一致。那条'如果'条款被推到那里,就像它被滑出了一样。 – tadman

+0

@tadman非常感谢您的建议。我同意你的看法,就像doc.at_css(...)没有找到任何东西。但如果我再次尝试寻找相同的交易,它确实给了我输出!我不明白。我也会更加注意缩进。 –

+0

欢迎来到SO。请阅读“[mcve]”和链接页面。您需要提供允许我们确认问题的代码。目前我们不能这样做,因为您没有告诉我们如何调用您的方法。 –

回答

4

一种方法是有点偏执:

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

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

几件事情要牢记在这里。在红宝石只有nilfalse逻辑上是错误的,所以它是非常罕见的,你需要专门测试nil?的东西。唯一必要的情况是,当你想区分nilfalse时,你可以想象它并不经常。

因此,在这种情况下,无论您是使用at_css还是未使用,在这种情况下try调用都不会执行任何操作。如果它发现某个try呼叫继续进行另一个呼叫。然后,您可以使用简单的||(或)运算符来执行任务,以优先选择它们。

另一件事是因为这段代码是在一个类的方法里面,随便使用实例变量可能会有麻烦。如果仅在此方法中使用purchase_link之类的内容,请删除使其持久化的@

另一件事要小心的是如何你的方法被定义为:

def self.deal_page(input, product_url) 

声明参数product_url,但里面:

html = open(@product_url) 

此引用类实例变量@product_url这是不一样。您可能在这里调用了错误的变量open

+2

请注意'.try()'是[Rails](https://apidock.com/rails/v3.2.1/Object/try)方法,而不是核心Ruby方法。 '[安全导航运算符](http://stackoverflow.com/questions/36812647/what-does-ampersand-dot-mean-in-ruby)与'doc.at_css()&。attr() '。 – anothermh

+0

2.3引入了安全导航操作符,它实际上比'try'更加连贯。我忘了这是Rails的具体。 – tadman

+1

@tadman此解决方案的工作原理!我非常感谢你的时间和建议。 –

0

当你的堆栈跟踪显示该行导致该错误:

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

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

您可以通过打印的

doc.at_css("div.detailLeftColumn a.success") 

值对于您可以参考http://www.nokogiri.org/tutorials/更多信息调试此。为解决这一问题

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,它返回一个节点集

doc.css('h1').class # => Nokogiri::XML::NodeSet 

然后text其串接在节点集,这是几乎总是所有文字不是你想做什么。试想一下:

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),除了那罕见情况下,你知道文本实际上需要连接。我只会遇到这种情况......哦......永远不会。

相关问题