【Ruby】NokogiriでHTMLを正しく切り詰める方法

S 20240202 205849

NokogiriはRubyでHTML/XMLを解析するためのライブラリです。

Railsアプリケーションの場合、自分で使っていなくて、使用しているGemのどれかが依存している場合があり、自動的にインストールする羽目になったという方も多いかもしれません。

NokogiriはWebドキュメントを解析し、特定の要素を検索したり抽出したりする場合に使用できますが、閉じタグが省略されているなど不正なHTMLを読みこみ、正しい形に変換して出力することもできるようです。

これは例えば次のように実行します(参考: Fix invalid html using Nokogiri)。

doc = Nokogiri::HTML.parse(<<-eohtml)
<html>
  <head>
    <title>Hello World</title>
  <body>
    <h1>This is an awesome document</h1>
    <p>
      I am a paragraph
        <a href="http://google.ca">I am a link</a>
    <table><tr><td>table content!
  </body>
eohtml
    valid_html = doc.to_s
    puts valid_html

実行すると、tableタグやhtmlタグなど、省略されていた閉じタグが追加されたHTMLが出力されます。


<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
  <head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Hello World</title>
  </head>
<body>
    <h1>This is an awesome document</h1>
    <p>
      I am a paragraph
        <a href="http://google.ca">I am a link</a>
    </p>
<table><tr><td>table content!
  </td></tr></table>
</body>
</html>

この機能を利用してHTMLを切り詰めることもできます。

HTMLを切り詰めることもできる

以下のプログラムはRailsアプリケーションを想定しています。truncateで文字列を短くしたあと、Nokogiri::HTML.parseを呼び出しています。

html=<<eohtml
<html>
  <head>
    <title>ハーローワールド</title>
  <body>
    <h1>テスト用ドキュメントです</h1>
    <ul>
      <li>aaaaaaaaaaaaaaaaaaaa</li>
      <li>bbbbbbbbbbbbbbbbbbbb</li>
      <li>cccccccccccccccccccc</li>
      <li>dddddddddddddddddddd</li>
    <table>
        <tr><td>table content 1!</td>
        <tr><td>table content 2
  </body>
eohtml
    str = html.truncate(220, omission: '')
    doc2 = Nokogiri::HTML.parse(str)
    puts doc2.to_s
    puts doc2.to_s.length

実行結果です。

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
  <head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>ハーローワールド</title>
  </head>
<body>
    <h1>テスト用ドキュメントです</h1>
    <ul>
      <li>aaaaaaaaaaaaaaaaaaaa</li>
      <li>bbbbbbbbbbbbbbbbbbbb</li>
      <li>cccccccccccccccccccc</li>
      <li>dddddddddddddd</li>
</ul>
</body>
</html>
431

元々のHTMLは短くなっていることがわかります。ただし、DOCTYPEやmetaタグ、閉じタグが追加されたせいで、全体の文字数は431文字まで増えています。最終的な結果を指定文字数までに抑えたい場合、さらに処理が必要となります。