如何使用Nokogiri从HTML头获取规范链接

时间:2016-11-16 18:16:38

标签: html ruby nokogiri

我正在尝试使用Nokogiri从网页获取已定义的规范链接:

<link rel="canonical" href="https://test.com/somepage">

这是href我追求的。

无论我尝试什么,它似乎都不起作用。这就是我所拥有的:

page = Nokogiri::HTML.parse(browser.html)

canon = page.xpath('//canonical/@href')
puts canon 

这不会返回任何内容,甚至不会返回错误。

2 个答案:

答案 0 :(得分:3)

您正在尝试获取该属性,但这不是您的操作方式。

您可以使用:

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”的节点,而不是属性。

答案 1 :(得分:1)

我喜欢在XPath上使用CSS选择器,因为它们更具可读性:

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对象的列表。通常,NodeSet通过Nokogiri :: XML :: Searchable#css或Nokogiri :: XML :: Searchable #xpath

搜索文档后返回

如果您要查找特定节点,或仅查找特定类型节点的单个实例,请使用at,或者如果您想挑剔,请使用at_css或{{3 }}。 (Nokogiri通常可以弄清楚你在使用atsearch时的意思,但有时你必须使用特定的方法让Nokogiri在正确的方向上轻推。)使用at上面的示例显示它返回节点本身,一旦您获得了节点,通过将其视为散列来获取任何参数的值是微不足道的。

xpathsearchcss都返回NodeSet,因此,就像数组一样,您需要指向您想要的实际元素,然后访问参数:

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会对它进行字符串化处理,但是如果你试图像对待它一样,它就不会像String一样导致错误。例如:

doc.xpath('//link[@rel="canonical"]/@href').first.downcase # => NoMethodError: undefined method `downcase' for #<Nokogiri::XML::Attr:0x007faace115d20>

而是使用at_xpathcontent获取文本值:

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,我只获取Node本身,然后使用['href']返回参数的文本。它是一个更短的选择器,更有意义,至少对我来说,因为Nokogiri不必返回Attr对象,然后你必须使用text进行转换,或者当你意外时可能遇到问题把它当作一个字符串。