こんにちは。エンジニアの高橋です。
突然ですが、スクレイピング先のページがこんなページだったらどうしますか?

<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<table border="1">
    <tr>
        <td>
            きのこ
        </td>
        <td></td>
    </tr>
    <td>
        たけのこ
    </td>
    <td></td>
    </tr>
</table>
</body>
</html>

シンプルなテーブルです。ただ、tr開始タグがないようです。

こんなページに遭遇したことはないですか?それはあなたが今まで幸運だっただけかもしれません。このような壊れたタグを返してくるサイトが、たまにあるんです・・・

壊れたタグがあるhtmlをNokogiriでパースすると?

以下のプログラムを動かします。

require "nokogiri"

html = <<~EOF
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<table border="1">
    <tr>
        <td>
            きのこ
        </td>
        <td></td>
    </tr>
    <td>
        たけのこ
    </td>
    <td></td>
    </tr>
</table>
</body>
</html>
EOF

doc = Nokogiri::HTML.parse(html)

tr_n = doc.css("tr").size
puts "#{tr_n}個のtrを取得した"
puts doc.css("tr").map(&:text).join(",")

実行結果

1個のtrを取得した

        
            きのこ
        
        
            山
        
    

このように、壊れたタグはパースできていないことがわかります。

壊れたタグをChromeで開いてみる

Chromeで開いて見てください。

「たけのこ」も表として表示されています。

chrome開発者ツールで見ても、タグが修復されていることがわかります。

このように、Chromeは壊れたhtmlを自動で修復する機能があります。
(右クリック=>ページのソースを表示)で、修復前の壊れたhtmlを見ることができます。

Chromeのタグ修復機能を利用したhtml修正ツール

以下ソースです。
https://github.com/mmmmmavo/html_repairer

このHTMLRepaierを使用して見ます。

require "nokogiri"
require "./html_repairer/main"

html = <<~EOF
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<table border="1">
    <tr>
        <td>
            きのこ
        </td>
        <td></td>
    </tr>
    <td>
        たけのこ
    </td>
    <td></td>
    </tr>
</table>
</body>
</html>
EOF

r = HTMLRepairer.new
fixed = r.fix(html)

puts "==修復結果=="
puts fixed

doc = Nokogiri::HTML.parse(fixed)

tr_n = doc.css("tr").size
puts "#{tr_n}個のtrを取得した"
puts doc.css("tr").map(&:text).join(",")

出力結果です。tr開始タグが修復され、「たけのこ」をパースできました!

==修復結果==
<html><head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<table border="1">
    <tbody><tr>
        <td>
            きのこ
        </td>
        <td></td>
    </tr>
    <tr><td>
        たけのこ
    </td>
    <td></td>
    </tr>
</tbody></table>


</body></html>
2個のtrを取得した

        
            きのこ
        
        
            山
        
    ,
        たけのこ
    
    
        里
    
    

注意点
Chrome/selenium実行環境が必要です。
つまり、chromedriver/chromeのインストールが必要です。
環境構築は以下をご参照ください。

CentOS編 Ubuntu編 Mac編