我正在尝试使用Nokogiri从网页获取已定义的规范链接:
<link rel="canonical" href="https://test.com/somepage">
这是href
我追求的。
无论我尝试什么,它似乎都不起作用。这就是我所拥有的:
page = Nokogiri::HTML.parse(browser.html)
canon = page.xpath('//canonical/@href')
puts canon
这不会返回任何内容,甚至不会返回错误。
答案 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通常可以弄清楚你在使用at
或search
时的意思,但有时你必须使用特定的方法让Nokogiri在正确的方向上轻推。)使用at
上面的示例显示它返回节点本身,一旦您获得了节点,通过将其视为散列来获取任何参数的值是微不足道的。
xpath
,search
和css
都返回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_xpath
或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,我只获取Node本身,然后使用['href']
返回参数的文本。它是一个更短的选择器,更有意义,至少对我来说,因为Nokogiri不必返回Attr对象,然后你必须使用text
进行转换,或者当你意外时可能遇到问题把它当作一个字符串。