xpathで正規表現を使うapiは策定されているみたい(しらんけど)だけれど、ほとんどの環境でサポートされていない。
xpathで正規表現を使えると、複雑な条件をシンプルに指定できて幸せになれる(かもしれない)。
nokogiriではxpathの拡張ができるので、独自のapiをなんでも定義できる。
それをつかって正規表現を独自にサポートすることも可能である。
大したあれじゃないけど、クローラとかの実装でいろいろ役に立つので、スニペットとしてシェアしとく。
api
Nokogiri_opt = Class.new {
def _extract_tgt(node, prop)
tgt = nil
if prop[0] == "@"
tgt = node[prop.slice(1, 1024)]
else
# if ['class'].include?(prop)
# puts("warn: xnoko xpath prop is #{prop}. I guess it is not intended.")
# end
tgt = node.send(prop)
end
return nil unless tgt
raise "tgt is not string. prop:#{prop}. tgt:#{tgt}" if tgt.class != String
tgt
end
def regex(node_set, arg, regex)
node_set.find_all do |node|
tgt = _extract_tgt(node, arg)
tgt =~ /#{regex}/
end
end
def iregex(node_set, arg, regex)
node_set.find_all do |node|
tgt = _extract_tgt(node, arg)
tgt =~ /#{regex}/i
end
end
}.new
def xnoko(doc, xpath)
doc.xpath(xpath, Nokogiri_opt)
end
def xnoko0(doc, xpath)
xnoko(doc, xpath).first
end
how to use
html = File.open('/tmp/a.html').read
doc = Nokogiri::HTML(html)
xnoko(doc, '//*[ regex(., "name", "a|span") and text()="ugg" ]') # a or spanタグ
xnoko(doc, '//a[ regex(., "text", "パターソンの妻は遊んでばかり") ]')
xnoko(doc, '//a[ regex(., "@href", "^http") ]')
xnoko(doc, '//div[ iregex(., "@class", "islarge") ]')
xnoko(doc, ' //a[ regex(., "@href", "^\s*http:.+/xx_(?:md|dt)_index/xx_(?:md|dt)_list/xx_(?:md|dt)_info/") ] ').each do |x|
puts x[:href]
end