zackey推し

IT系のこと書くぞい

【Ruby】gem「nokogiri」を使ってHTML要素を抜き出す

f:id:kic-yuuki:20190618091152p:plain

bundle installした時にRubyのバージョンがあってなくて「nokogiriのインストールが終わらん〜」って悶絶するかたをよく見る気がします。

今回は、お仕事で例のnokogiriを調査→使うシーンがありましたので、調査時のメモを書き残しておこうかなと思います。

この記事なに? 🤔

Rubyのgem「nokogiri」を使ってHTML要素を抜き出す、というやり方を記載する記事になります。

nokogiriとは?

HTML / XMLといったDOM構造を持つドキュメントから、要素を抜き出せるGemのようです。

※ちなみに、nokogiriは日本語のが発祥っぽいですね。

公式サイト、リポジトリはこちらから。

実際に動かしてみる

では、以下のリポジトリに格納されているhtmlから、実際にHTML要素を抜き出してみます。

サンプルコード

要素を抜き出す対象のhtml

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
  </head>
  <body>
    Nokogiriテスト
    <input type="hidden" name="hidden_name" value="hidden_name" />
    <input type="hidden" id="hidden_id" value="hidden_id" />
    <div class="nokogiri">
      test
    </div>
  </body>
</html>

nokogiriを使ったrubyのソース

require 'nokogiri'

# index.htmlを読み込み
html = open('./index.html', &:read)

doc = Nokogiri::HTML.parse(html, nil)
doc.search('input').each do |element|
  puts "element.attributes: #{element.attributes}"
  puts "type: #{element.attributes['type'].value}"
  puts "name: #{element.attributes['name'].value}" if element.attributes['name']
  puts "id: #{element.attributes['id'].value}" if element.attributes['id']
  puts "value: #{element.attributes['value'].value}"
end

doc.css('.nokogiri').each do |element|
  puts "element.attributes: #{element.attributes}"
  puts "element.content: #{element.content}"
end

結果

# 1つめのループ
element.attributes: {"type"=>#<Nokogiri::XML::Attr:0x3feb26ca60ec name="type" value="hidden">, "name"=>#<Nokogiri::XML::Attr:0x3feb26ca60d8 name="name" value="hidden_name">, "value"=>#<Nokogiri::XML::Attr:0x3feb26ca60b0 name="value" value="hidden_name">}
type: hidden
name: hidden_name
value: hidden_name
element.attributes: {"type"=>#<Nokogiri::XML::Attr:0x3feb26caa728 name="type" value="hidden">, "id"=>#<Nokogiri::XML::Attr:0x3feb26caa714 name="id" value="hidden_id">, "value"=>#<Nokogiri::XML::Attr:0x3feb26caa6d8 name="value" value="hidden_id">}
type: hidden
id: hidden_id
value: hidden_id

# 2つめのループ
element.attributes: {"class"=>#<Nokogiri::XML::Attr:0x3feb26cb23c4 name="class" value="nokogiri">}
element.content: 
      test

使い方まとめ

実際に使ってみて、自分なりにnokogiriの使い方をまとめてみると、以下のようになりました。

  • 要素の特定方法
    • HTMLタグで特定したい場合は search を使う
    • クラスで特定したい場合は css を使う
  • Nokogiri::XML::Attrから特定の値を抜き出す場合
    • 属性値(name / id / typeなど)を抽出したい場合はattributes['要素名'].value
    • タグ内の値(<div>value</div>value)を抽出したい場合はcontent

※上記は、必要に応じて追記していくかもです。

おわり

nokogiri、使い勝手いいなーという感想です。

今回、大きいDOMを扱うわけでもないので、パフォーマンス面は調査しませんでしたが、速度的にはどうなんだろう。と思っていたら、nokogiriのパフォーマンス測定を行っていた記事がありました。感謝感謝。

結果だけさらっと見た感じ、悪くなさそうですが、XMLを解析する場合はxpathメソッドを使って要素検索した方が速いっぽいですね。