MAGAZINE
ルーターマガジン
NokogiriでCSSセレクタとノードの深さを取得する方法
こんにちは。学生エンジニアのKawaguchiです。
今回は、Nokogiriを用いてCSSセレクタを取得するメソッドと、ノードの深さを取得する方法を紹介します。
Nokogiriについてはこちらの記事を参考にしてください。
css_pathメソッドについて
Nokogiriにはcss_path
という標準メソッドがあり、
このメソッドはノードのhtmlタグまでのCSSセレクタ (例: html > body > div > div:nth-of-type(1) > p:nth-of-type(1)) を返してくれます。(classとidは取得出来ません。)
そして、CSSセレクタの「>」を数えるという単純な方法ですが、ノードの深さを取得することが出来ます。
ノードの深さを取得するサンプルコード
今回はこちらのsample.htmlというHTMLを対象にしていきます。
<html>
<body>
<div id="main">
<h1>商品一覧</h1>
<div>
<p class="name">商品名1</p>
<p class="price">価格1</p>
</div>
<div>
<p class="name">商品名2</p>
<p class="price">価格2</p>
</div>
</div>
</body>
</html>
require 'nokogiri'
html = open('sample.html').read
doc = Nokogiri::HTML.parse(html)
doc.css('p').each do |node|
puts node.text
puts node.css_path
puts node.css_path.count('>') + 1
puts ''
end
このように、CSSセレクタでpタグを指定し、ノードのテキスト、CSSセレクタ、ノードの深さを出力させると、以下のような結果が得られます。
html > body > div > div:nth-of-type(1) > p:nth-of-type(1)
5
価格1
html > body > div > div:nth-of-type(1) > p:nth-of-type(2)
5
商品名2
html > body > div > div:nth-of-type(2) > p:nth-of-type(1)
5
価格2
html > body > div > div:nth-of-type(2) > p:nth-of-type(2)
5
ノードの深さは無事に取得出来るようになったのですが、
classとid付きのCSSセレクタを別途利用することになり、css_pathメソッドでは、
classやidを取得することができないので、他にいいメソッドがないか調べてみました。
しかし、見つからなかったので、classとidも取得可能なメソッドを作成しました。
classとid付きのCSSセレクタを取得するメソッドについて
作成したのはcss_path_with_class_id
というメソッドで、簡単に説明すると、
引数のnodeからcss_pathメソッドで得られるCSSセレクタを「 > 」で区切った配列にし、
それぞれのタグの後に、classは「.」、idは「#」を前に付加し、追加させています。
require 'nokogiri'
def css_path_with_class_id(node)
tag_with_class_id_array = []
node.css_path.split(' > ').reverse.each do |tag|
tag += ".#{node['class']}" if node['class']
tag += "\##{node['id']}" if node['id']
tag_with_class_id_array << tag
node = node.parent
end
tag_with_class_id_array.reverse.join(' > ')
end
html = open('sample.html').read
doc = Nokogiri::HTML.parse(html)
doc.css('p').each do |node|
puts node.text
puts node.css_path
puts css_path_with_class_id(node)
puts ''
end
先ほどのように、CSSセレクタでpタグを指定し、出力させると、
html > body > div > div:nth-of-type(1) > p:nth-of-type(1)
html > body > div#main > div:nth-of-type(1) > p:nth-of-type(1).name
価格1
html > body > div > div:nth-of-type(1) > p:nth-of-type(2)
html > body > div#main > div:nth-of-type(1) > p:nth-of-type(2).price
商品名2
html > body > div > div:nth-of-type(2) > p:nth-of-type(1)
html > body > div#main > div:nth-of-type(2) > p:nth-of-type(1).name
価格2
html > body > div > div:nth-of-type(2) > p:nth-of-type(2)
html > body > div#main > div:nth-of-type(2) > p:nth-of-type(2).price
classとid付きのCSSセレクタを得られるようになりました。
さいごに
こうしたDOM構造の特徴解析など、様々な自前技術を盛り込んだのがルーターイチオシのAIクローラーです!これまでの定型的な情報収集だけのクローラーから1歩も2歩も進化し、例えば「会社の役職がある人の情報」という指定で自動的にインターネットの公開情報の中から情報を収集したりできるようになります。
弊社エンジニアは今後も「一つ先を行くクローラー」の開発を行っていきます!クローリング/スクレイピングのお悩みがあればぜひお問い合わせ下さい。
CONTACT
お問い合わせ・ご依頼はこちらから