Css nil:NilClass(NoMethodError)的未定义方法“attr”

Css nil:NilClass(NoMethodError)的未定义方法“attr”,css,ruby,nokogiri,open-uri,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[:dis

我的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,至少是css,除非,如果..否则,但是没有帮助。另外,我并不是每次都会遇到这个错误,但我想消除它。

因为堆栈跟踪显示这一行是导致错误的原因:

@purchase_link= doc.at_css("div.detailLeftColumn a.success").attr("href")
无法对nil调用attr方法。查看HTML中是否存在该元素

您可以通过打印

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

有关更多信息,请参阅。

当堆栈跟踪显示此行导致错误时:

@purchase_link= doc.at_css("div.detailLeftColumn a.success").attr("href")
无法对nil调用attr方法。查看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在逻辑上是false,所以很少需要专门测试nil?在一些事情上。唯一必要的情况是当您想要区分nil和false时,正如您所想象的,这并不经常发生

因此,在本例中,要么使用at_css命中某个对象,要么不命中,在这种情况下,try调用不起任何作用。如果它发现了什么,try调用将继续进行一次调用。然后,您可以使用简单的| |或运算符执行赋值,以优先选择它们

另一件事是,由于该代码位于类方法内部,随意使用实例变量可能会带来麻烦。如果像purchase_link这样的东西只在这个方法中使用,那么删除@使它们持久化

另一件需要注意的事情是如何将您的方法定义为:

def self.deal_page(input, product_url)
声明了一个参数product_url,但在内部:

html = open(@product_url)

这引用了不同的类实例变量@product_url。您可能在此处使用错误的变量调用open。

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

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

deal[:purchase] = @purchase_link || @product_url
这里有几件事要记住。在Ruby中,只有nil和false在逻辑上是false,所以很少需要专门测试nil?在一些事情上。唯一必要的情况是当您想要区分nil和false时,正如您所想象的,这并不经常发生

因此,在本例中,要么使用at_css命中某个对象,要么不命中,在这种情况下,try调用不起任何作用。如果它发现了什么,try调用将继续进行一次调用。然后,您可以使用简单的| |或运算符执行赋值,以优先选择它们

另一件事是,由于该代码位于类方法内部,随意使用实例变量可能会带来麻烦。如果像purchase_link这样的东西只在这个方法中使用,那么删除@使它们持久化

另一件需要注意的事情是如何将您的方法定义为:

def self.deal_page(input, product_url)
声明了一个参数product_url,但在内部:

html = open(@product_url)

这引用了不同的类实例变量@product_url。您可能在此处使用错误的变量调用open。

我认为问题在于:

def self.deal_page(input, product_url)
  ...
  html = open(@product_url)
您正在使用product\u url作为参数,但正在尝试打开@product\u url

如果@product\u url为空或为零,则open将引发错误,因此必须在某个地方预定义@product\u url,但显然不是在该方法中。我怀疑它不是您所想的页面,因此选择器失败

您的代码中还有其他问题:

deal[:name] = doc.css("h1").text.strip
deal[:discription] = doc.css(".textDescription").text.strip
您正在使用,它返回一个节点集

doc.css('h1').class # => Nokogiri::XML::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>
css'h1'。文本连接foo和bar,生成foobar。一旦发生这种情况,就很难解开由串联引起的混乱


相反,您应该使用doc.css'h1'.map&:text,除非您知道文本实际上需要连接在一起。我只是遇到过那种情况。。。哦从不重复。

我认为问题在于:

def self.deal_page(input, product_url)
  ...
  html = open(@product_url)
您正在使用product\u url作为参数,但正在尝试打开@product\u url

如果@product\u url为空或为零,则open将引发错误,因此必须在某个地方预定义@product\u url,但显然不是在该方法中。我怀疑它不是您所想的页面,因此选择器失败

您的代码中还有其他问题:

deal[:name] = doc.css("h1").text.strip
deal[:discription] = doc.css(".textDescription").text.strip
您正在使用,它返回一个节点集

doc.css('h1').class # => Nokogiri::XML::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>
css'h1'。文本连接foo和bar,生成foobar。一旦发生这种情况,就很难解开由串联引起的混乱

相反,您应该使用doc.css'h1'.map&:text,除非您知道文本实际上需要连接在一起。我只是遇到过那种情况。。。哦从不重复。

当遇到像这样的零问题时,退回一次操作,看看是什么很重要
未能参与。看起来像是医生在。。。什么也没找到。另一件需要注意的事情是尽量保持缩进的一致性。“若条款被塞进那个里,就像它滑出了位置一样。”塔德曼非常感谢你们的建议。我同意你的看法,它看起来像是doc.at_css。。。什么也没找到。但如果我再次尝试寻找相同的交易,它确实会给我输出!我不明白。我也会更加小心缩进。欢迎来到SO。请阅读和链接页面。您需要提供允许我们确认问题的代码。目前我们无法这样做,因为您没有告诉我们如何调用您的方法。当遇到像这样的nil问题时,请后退一步,看看哪些操作失败。看起来像是医生在。。。什么也没找到。另一件需要注意的事情是尽量保持缩进的一致性。“若条款被塞进那个里,就像它滑出了位置一样。”塔德曼非常感谢你们的建议。我同意你的看法,它看起来像是doc.at_css。。。什么也没找到。但如果我再次尝试寻找相同的交易,它确实会给我输出!我不明白。我也会更加小心缩进。欢迎来到SO。请阅读和链接页面。您需要提供允许我们确认问题的代码。目前我们无法这样做,因为您没有告诉我们如何调用您的方法。请注意。try是一个方法,而不是核心Ruby方法。与doc.at_css&.attr.2.3相当的是Ruby,它引入了安全导航操作符,实际上比try更加连贯。我忘了这是Rails特有的。@tadman此解决方案有效!我真的很感谢你的时间和建议。@Anotherh非常感谢。我不熟悉安全导航操作员。请注意,try是一个方法,而不是核心Ruby方法。与doc.at_css&.attr.2.3相当的是Ruby,它引入了安全导航操作符,实际上比try更加连贯。我忘了这是Rails特有的。@tadman此解决方案有效!我真的很感谢你的时间和建议。@Anotherh非常感谢。我不熟悉安全导航操作员。我会记住这一点。