Ruby 从HTML解析价格返回空值还是无值?

Ruby 从HTML解析价格返回空值还是无值?,ruby,nokogiri,screen-scraping,mechanize,Ruby,Nokogiri,Screen Scraping,Mechanize,我没有看到任何成功,因为无论我做什么,它只返回空白值 这是我的密码: require 'rubygems' require 'nokogiri' require 'open-uri' PAGE_URL = "http://www.oficinadosbits.com.br/produto18064/EVGA_GeForce_GTX_980_04G-P4-2983-KR.html" page = Nokogiri::HTML(open(PAGE_URL)) price = page.xpat

我没有看到任何成功,因为无论我做什么,它只返回空白值

这是我的密码:

require 'rubygems'
require 'nokogiri'
require 'open-uri'

PAGE_URL = "http://www.oficinadosbits.com.br/produto18064/EVGA_GeForce_GTX_980_04G-P4-2983-KR.html"

page = Nokogiri::HTML(open(PAGE_URL))

price = page.xpath("/html/body/div[1]/div/div/table[1]/tbody/tr[1]/td[3]/table[1]/tbody/tr[2]/td[3]/table[1]/tbody/tr/td[1]/font[2]/table/tbody/tr[1]/td/span").text

puts price
我尝试过使用CSS和Mechanize,但没有成功:

require 'rubygems'
require 'nokogiri'
require 'open-uri'
require 'mechanize'

mechanize = Mechanize.new

page = mechanize.get("http://www.oficinadosbits.com.br/produto18064/EVGA_GeForce_GTX_980_04G-P4-2983-KR.html")

doc = page.parser

price = doc.xpath("/html/body/div[1]/div/div/table[1]/tbody/tr[1]/td[3]/table[1]/tbody/tr[2]/td[3]/table[1]/tbody/tr/td[1]/font[2]/table/tbody/tr[1]/td/span").text

puts price
当我使用:

puts price.size
最后它返回一个零。为什么它读取的值为零

我想了解为什么会发生这种情况,以及我如何解决它,以便能够分析价格


我从Firebug的“复制xpath”选项获得xpath。

/html/body/div[1]/div/div/table[1]
中没有
tbody
。但是你可以自己检查一下

page.xpath("/html/body/div[1]/div/div/table[1]")
# => lots of output
page.xpath("/html/body/div[1]/div/div/table[1]/tbody")
# => whoopsie.

问题是,FireBug的“复制XPath”将为您提供DOM的XPath,就像您请求时浏览器中的一样,这可能与源文档的DOM不同,原因有很多:例如,JavaScript更改了DOM,或浏览器自动插入的某些节点。

/html/body/div[1]/div/div/table[1]
中没有
tbody
。但是你可以自己检查一下

page.xpath("/html/body/div[1]/div/div/table[1]")
# => lots of output
page.xpath("/html/body/div[1]/div/div/table[1]/tbody")
# => whoopsie.

问题是,FireBug的“复制XPath”将为您提供DOM的XPath,就像您请求时浏览器中的一样,这可能与源文档的DOM不同,原因有很多:例如,JavaScript更改了DOM,或者浏览器自动插入了某些节点。

如果您想获得以下价格:

"GeForce GTX 980 4GB GDDR5 256bits - Game Grátis - EVGA 04G-P4-2983-KR" 
您可以将Nokogiri与CSS选择器一起使用:

doc = Nokogiri::HTML(open("http://www.oficinadosbits.com.br/produto18064/EVGA_GeForce_GTX_980_04G-P4-2983-KR.html"))
price = doc.css("html > body > div")[0].css("div > div > table[1] > tr")[0].css("td[3] > table")[1].css("tr > td")[1].css("span")[0].text

如果您想获得以下产品的价格:

"GeForce GTX 980 4GB GDDR5 256bits - Game Grátis - EVGA 04G-P4-2983-KR" 
您可以将Nokogiri与CSS选择器一起使用:

doc = Nokogiri::HTML(open("http://www.oficinadosbits.com.br/produto18064/EVGA_GeForce_GTX_980_04G-P4-2983-KR.html"))
price = doc.css("html > body > div")[0].css("div > div > table[1] > tr")[0].css("td[3] > table")[1].css("tr > td")[1].css("span")[0].text

该页面上有大量有用的css:

page.at('[itemprop=price]').text
#=> "R$ 3.459,90"

该页面上有大量有用的css:

page.at('[itemprop=price]').text
#=> "R$ 3.459,90"

Nokogiri同时支持XPath和CSS选择器。为了可读性和简单性,我通常使用CSS,但是XPath也很重要,因为它有很多功能

考虑以下代码:

require 'nokogiri'

doc = Nokogiri::HTML(<<EOT)
<html>
  <body>
    <p id="p1" class="paragraphs" foo="bar">some text</p>
    <p id="p2" class="paragraphs" foo="baz">some text</p>
  </body>
</html>
EOT
at
相当于获取
search
找到的第一个元素,但它返回一个元素/节点。一个节点可以包含更多的节点/标记,一个节点集可以是一个节点数组,在所有情况下,一个节点就像指向文档的指针,对四处导航很有用

doc.at('body').at('p') # => #<Nokogiri::XML::Element:0x3fd431448c6c name="p" attributes=[#<Nokogiri::XML::Attr:0x3fd431448c08 name="id" value="p1">, #<Nokogiri::XML::Attr:0x3fd431448bf4 name="class" value="paragraphs">, #<Nokogiri::XML::Attr:0x3fd431448be0 name="foo" value="bar">] children=[#<Nokogiri::XML::Text:0x3fd431448384 "some text">]>
doc.at('body > p')     # => #<Nokogiri::XML::Element:0x3fd431448c6c name="p" attributes=[#<Nokogiri::XML::Attr:0x3fd431448c08 name="id" value="p1">, #<Nokogiri::XML::Attr:0x3fd431448bf4 name="class" value="paragraphs">, #<Nokogiri::XML::Attr:0x3fd431448be0 name="foo" value="bar">] children=[#<Nokogiri::XML::Text:0x3fd431448384 "some text">]>
doc.at('p')            # => #<Nokogiri::XML::Element:0x3fd431448c6c name="p" attributes=[#<Nokogiri::XML::Attr:0x3fd431448c08 name="id" value="p1">, #<Nokogiri::XML::Attr:0x3fd431448bf4 name="class" value="paragraphs">, #<Nokogiri::XML::Attr:0x3fd431448be0 name="foo" value="bar">] children=[#<Nokogiri::XML::Text:0x3fd431448384 "some text">]>
在上述结果中保持不变

在此基础上,要在HTML中查找节点,我们可以使用各种参数进行导航:

doc.at('p[foo="baz"]').to_html # => "<p id=\"p2\" class=\"paragraphs\" foo=\"baz\">some text</p>"

doc.search('p[foo="baz"]').size # => 1
doc.search('p[foo="baz"]').first.to_html # => "<p id=\"p2\" class=\"paragraphs\" foo=\"baz\">some text</p>"

Nokogiri同时支持XPath和CSS选择器。为了可读性和简单性,我通常使用CSS,但是XPath也很重要,因为它有很多功能

考虑以下代码:

require 'nokogiri'

doc = Nokogiri::HTML(<<EOT)
<html>
  <body>
    <p id="p1" class="paragraphs" foo="bar">some text</p>
    <p id="p2" class="paragraphs" foo="baz">some text</p>
  </body>
</html>
EOT
at
相当于获取
search
找到的第一个元素,但它返回一个元素/节点。一个节点可以包含更多的节点/标记,一个节点集可以是一个节点数组,在所有情况下,一个节点就像指向文档的指针,对四处导航很有用

doc.at('body').at('p') # => #<Nokogiri::XML::Element:0x3fd431448c6c name="p" attributes=[#<Nokogiri::XML::Attr:0x3fd431448c08 name="id" value="p1">, #<Nokogiri::XML::Attr:0x3fd431448bf4 name="class" value="paragraphs">, #<Nokogiri::XML::Attr:0x3fd431448be0 name="foo" value="bar">] children=[#<Nokogiri::XML::Text:0x3fd431448384 "some text">]>
doc.at('body > p')     # => #<Nokogiri::XML::Element:0x3fd431448c6c name="p" attributes=[#<Nokogiri::XML::Attr:0x3fd431448c08 name="id" value="p1">, #<Nokogiri::XML::Attr:0x3fd431448bf4 name="class" value="paragraphs">, #<Nokogiri::XML::Attr:0x3fd431448be0 name="foo" value="bar">] children=[#<Nokogiri::XML::Text:0x3fd431448384 "some text">]>
doc.at('p')            # => #<Nokogiri::XML::Element:0x3fd431448c6c name="p" attributes=[#<Nokogiri::XML::Attr:0x3fd431448c08 name="id" value="p1">, #<Nokogiri::XML::Attr:0x3fd431448bf4 name="class" value="paragraphs">, #<Nokogiri::XML::Attr:0x3fd431448be0 name="foo" value="bar">] children=[#<Nokogiri::XML::Text:0x3fd431448384 "some text">]>
在上述结果中保持不变

在此基础上,要在HTML中查找节点,我们可以使用各种参数进行导航:

doc.at('p[foo="baz"]').to_html # => "<p id=\"p2\" class=\"paragraphs\" foo=\"baz\">some text</p>"

doc.search('p[foo="baz"]').size # => 1
doc.search('p[foo="baz"]').first.to_html # => "<p id=\"p2\" class=\"paragraphs\" foo=\"baz\">some text</p>"

欢迎来到堆栈溢出。我们不在乎你的经验,我们只想要深思熟虑的问题来显示你的努力。”“这就是原因。不要使用基于浏览器的工具获取HTML或确定选择器。浏览器会弄乱HTML,因此它显示的内容通常不可信。此外,使用“复制xpath”会产生一个长而脆弱的选择器。相反,使用
wget
curl
或Nokogiri本身检索页面,并在浏览器外部查看页面。然后找出文档中用于导航到所需节点的路径点。此外,当询问代码时,我们需要问题本身的最小输入数据和预期输出。请读“。它帮助我们帮助你,也帮助那些在未来试图解决同样问题的人。欢迎来到堆栈溢出。我们不在乎你的经验,我们只想要深思熟虑的问题来显示你的努力。”“这就是原因。不要使用基于浏览器的工具获取HTML或确定选择器。浏览器会弄乱HTML,因此它显示的内容通常不可信。此外,使用“复制xpath”会产生一个长而脆弱的选择器。相反,使用
wget
curl
或Nokogiri本身检索页面,并在浏览器外部查看页面。然后找出文档中用于导航到所需节点的路径点。此外,当询问代码时,我们需要问题本身的最小输入数据和预期输出。请读“。它帮助我们帮助你,也帮助那些未来试图解决同样问题的人。我的
css(…)[0]
at(…)
相同,因此请利用
at
及其变体。您选择节点的方法非常脆弱,因为页面中的更改将破坏它。相反,找到路径点并使用它们来定位所需的节点。请看@pguardiario的答案。非常感谢您的解释!我看到@pguardiario的解决方案非常干净。html上的小改动安全吗?哦。我的
css(…)[0]
at(…)
相同,因此请利用
at
及其变体。您选择节点的方法非常脆弱,因为页面中的更改将破坏它。相反,找到路径点并使用它们来定位所需的节点。请看@pguardiario的答案。非常感谢您的解释!我看到@pguardiario的解决方案非常干净。html上的小改动是否安全?我完全信任FireBug的“复制XPath”。正如我所说,我是一个初学者,并且认为问题可能是其他的。非常感谢这些提示!我完全信任FireBug的“复制XPath”。正如我所说,我是一个初学者,并且认为问题可能是其他的。非常感谢这些提示!哇,太简单了!这个真的帮助了我。你能给我解释一下为什么在这种情况下用括号代替括号吗?非常感谢。当然,属性总是放在括号中。如果你不熟悉这个,请阅读一些css文档。哇,太简单了!这