LoginSignup
2
0

More than 5 years have passed since last update.

xpathで正規表現を使いたい。Nokogiriにおける対応方法。

Last updated at Posted at 2018-05-15

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
2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0