我正在尝试从使用Nokogiri的网页中获得定义的规范链接:
<link rel="canonical" href="https://test.com/somepage">
我要找的是href
。
不管我怎么试,似乎都不起作用。这是我的文件:
page = Nokogiri::HTML.parse(browser.html)
canon = page.xpath('//canonical/@href')
puts canon
这不会返回任何东西,甚至没有错误。
您试图获得属性,但不是这样做的。
你可以这样写:
page.xpath('//link[@rel="canonical"]/@href')
它说的是:在文档的任何地方给我一个链接元素,它的rel
属性等于"canonical"
,当你找到那个节点时,给我它的href
属性。
完整答案为:
page = Nokogiri::HTML.parse(browser.html)
canon = page.xpath('//link[@rel="canonical"]/@href')
puts canon
您尝试做的是获得一个称为"canonical"的节点,而不是属性。
我喜欢使用CSS选择器而不是XPath,因为它们更具可读性:
require 'nokogiri'
doc = Nokogiri::HTML('<link rel="canonical" href="https://test.com/somepage">')
doc.at('link[rel="canonical"]')['href'] # => "https://test.com/somepage"
对于Nokogiri和XPath在访问节点参数时返回的内容存在混淆。想想看:
require 'nokogiri'
doc = Nokogiri::HTML('<link rel="canonical" href="https://test.com/somepage">')
下面是我使用CSS的方法:
doc.at('link[rel="canonical"]').class # => Nokogiri::XML::Element
doc.at('link[rel="canonical"]')['href'].class # => String
doc.at('link[rel="canonical"]')['href'] # => "https://test.com/somepage"
XPath虽然更强大,但也能够让您或Nokogiri、Ruby或CPU做更多的工作。
首先是xpath
,它是search
的xpath特定版本,返回NodeSet,而不是节点或元素。NodeSet类似于节点数组,如果您不知道自己得到了什么,可能会受到影响。来自NodeSet文档:
NodeSet包含Nokogiri::XML::Node对象的列表。通常,Nokogiri::XML::Searchable#css或Nokogiri::XML::Searchable#xpath
搜索文档的结果返回Nokogiri:: Searchable#xpath
如果您正在寻找一个特定的节点,或者只是特定类型节点的单个实例,那么使用at
,或者如果您想要挑剔,使用at_css
或at_xpath
。(当你使用at
或search
时,Nokogiri通常可以理解你的意思,但有时你必须使用特定的方法来推动Nokogiri朝正确的方向前进。)在上面的示例中使用at
显示它返回节点本身,一旦获得了节点,通过将其作为散列处理来获取任何参数的值就很简单了。
xpath
, search
和css
都返回NodeSets,因此,像数组一样,您需要指向您想要的实际元素,然后访问参数:
doc.xpath('//link[@rel="canonical"]/@href').class # => Nokogiri::XML::NodeSet
doc.xpath('//link[@rel="canonical"]/@href').first.class # => Nokogiri::XML::Attr
doc.xpath('//link[@rel="canonical"]/@href').text # => "https://test.com/somepage"
注意'//link[@rel="canonical"]/@href'
导致Nokogiri返回一个Attr对象,而不是文本。您可以打印该对象,Ruby将对其进行字符串化,但如果您试图将其视为字符串,则它的行为不会像字符串那样导致错误。例如:
doc.xpath('//link[@rel="canonical"]/@href').first.downcase # => NoMethodError: undefined method `downcase' for #<Nokogiri::XML::Attr:0x007faace115d20>
相反,使用text
或content
来获取文本值:
doc.at('//link[@rel="canonical"]/@href').class # => Nokogiri::XML::Attr
doc.at('//link[@rel="canonical"]/@href').text # => "https://test.com/somepage"
或者获取元素本身,然后像访问散列一样访问参数:
doc.at('//link[@rel="canonical"]').class # => Nokogiri::XML::Element
doc.at('//link[@rel="canonical"]')['href'] # => "https://test.com/somepage"
都将返回一个String。
还请注意,在本例中,我没有使用@href
返回Attr,我只获取节点本身,然后使用['href']
返回参数的文本。它是一个更短的选择器,更有意义,至少对我来说,因为Nokogiri不必返回Attr对象,然后你必须使用text
转换,或者当你意外地将其视为字符串时可能会遇到问题。