:在Nokogiri有CSS伪类
我正在寻找伪类:has
在Nokogiri有 。 它应该像jQuery的选择器一样工作。
例如:
ex1
sdfsdf ex2
ex3
CSS选择器应该只返回第一个链接,一个带有非空的span.string
兄弟。
在jQuery中,这个选择器运行良好:
$('li:has(span.string:not(:empty))>h1>a')
但不是在Nokogiri:
Nokogiri::HTML(html_source).css('li:has(span.string:not(:empty))>h1>a')
:not
and :empty
运行良好,但不是:has
。
- 在Nokogiri有CSS选择器的文档吗?
- 也许有人可以写一个自定义
:has
伪类吗? 以下是如何编写:regexp
选择器的示例 。 - 我可以选择使用XPath。 如何为
li:has(span.string:not(:empty))>h1>a
编写XPathli:has(span.string:not(:empty))>h1>a
?
Nokogiri当前实现的问题:has()
是它创建了XPath,要求内容是直接子,而不是任何后代:
puts Nokogiri::CSS.xpath_for( "a:has(b)" ) #=> "//a[b]" #=> Should output "//a[.//b]" to be correct
要使此XPath与jQuery相匹配,您需要允许span
作为后代元素。 例如:
require 'nokogiri' d = Nokogiri.XML(' ') d.at_css('a:has(b)') #=> #]>]> d.at_css('a:has(c)') #=> nil d.at_xpath('//a[.//c]') #=> # ]>]>
对于您的具体情况,这里是完整的“破损”XPath:
puts Nokogiri::CSS.xpath_for( "li:has(span.string:not(:empty)) > h1 > a" ) #=> //li[span[contains(concat(' ', @class, ' '), ' string ') and not(not(node()))]]/h1/a
在这里它是固定的:
# Adding just the .// //li[.//span[contains(concat(' ', @class, ' '), ' string ') and not(not(node()))]]/h1/a # Simplified to assume only one CSS class is present on the span //li[.//span[@class='string' and not(not(node()))]]/h1/a # Assuming that `not(:empty)` really meant "Has some text in it" //li[.//span[@class='string' and text()]]/h1/a # ..or maybe you really wanted "Has some text anywhere underneath" //li[.//span[@class='string' and .//text()]]/h1/a # ..or maybe you really wanted "Has at least one element child" //li[.//span[@class='string' and *]]/h1/a
Nokogiri没有:has
选择器,这里有关于它做什么的文档: http :has
//ruby.bastardsbook.com/chapters/html-parsing/#h-2-2
好的,我找到了一个可能对某人有用的解决方案。
自定义伪类:custom_has
:
class MyCustomSelectors def custom_has node_set, selector node_set.find_all { |node| node.css(selector).present? } end end #usage: doc.css('li:custom_has(span.string:not(:empty))>h1>a',MyCustomSelectors.new)
我为什么声明:custom_has
不仅仅是:has
吗? 因为它已经宣布了。 在Nokogiri repo中测试 :has
选择器,但它们不起作用。 我向作者报告了这个问题 。
Nokogiri允许在同一对象上链接.css()
和.xpath()
。 因此,只要你想使用:has
,只需结束当前的.css()
调用并添加.xpath(..)
(父选择器)。 您甚至可以从另一个.css()
调用恢复您的选择,从xpath()
停止开始!
例:
这是来自维基百科的一些HTML:
Origin Edinburgh Scotland Genres Electronica IDM ambient downtempo trip hop Labels Warp Skam Music70
假设您要选择包含href="/Music_genre"
链接的
之后的
一个
@artistPage.css("table th > a[href='https://stackoverflow.com/wiki/Music_genre']").xpath("..").css("+ td a")
现在好好衡量一下,让我们抓住所有那些的内部文本并将它们放在一个数组中。
@genreLinks = @artistPage.css("table th > a[href='https://stackoverflow.com/wiki/Music_genre']").xpath("..").css("+ td a") @genres = [] @genreLinks.each do |genreLink| @genres.push(genreLink.text) end