LoginSignup
0
0

More than 3 years have passed since last update.

Ruby : Nokogiriはバイナリモードで読んだhtmlの文字コードを自動で判別しにいく

Posted at

はじめに

open-uriでhtmlを読み込み、Nokogiriでパースしてスクレイピングを行っていたのですが、その際Nokogiriのエンコーディングをnilに(もしくは省略)しても文字化けを起こすことなくパースができていました。
open-uriでhtmlを読むときはバイナリで読み込まれるので、バイナリで読み込まれたhtmlを、エンコーディングnilにしてNokogiriでパースするとどうなるか、ということに焦点をしぼって検証してみました。

HTML.parseのエンコーディングを「nil」にしてみる

Nokogiriでhtmlをパースするときのエンコーディングをnilとしてみます。HTML.parseの第三引数にnilを設定します。
今回読み込むのは以下のhtmlです。ファイルはShift_JISで書かれています。

hello.html
<html>
  <head>
    <title>こんにちわ</title>
    <meta charset="Shift_JIS">
  </head>
  <body>
  </body>
</html>

バイナリモードでhtmlを読み込みます。openメソッドに'rb'オプションを追記することでバイナリでファイルを読むことができます。
検証のため、バイナリモードで読み込んだ時点での文字コードと、Nokogiriでパースしたあとの文字コードを表示してみます。

sample.rb
require 'nokogiri'

html = open('hello.html', 'rb').read

p html.encoding
p Nokogiri::HTML.parse(html, nil, nil).encoding

実行結果

sample.rbの結果
$ ruby sample.rb
#<Encoding:ASCII-8BIT>
"Shift_JIS"

結果からは、読み込んだhtml自体のエンコーディングはASCII-8BITですが、Nokogiriによってパースされたあとのエンコーディングは元ファイルと同じShift_JISとなっていることが確認できます。
ちなみにHTML.parse(html)として引数を省略した場合でも、上記と同じ結果が得られます。

Nokogiriはどこで文字コードを参照しているか

さきほどの検証結果を見るに、Nokogiriはどこかの文字コードを自分で参照しに行っています。どこを参照しているのか。

実は元のhtmlファイルのmeta要素を参照しに行っています。
<meta charset="Shift_JIS">のcharsetを参照しているというわけです。

試しにcharset部分をUTF-8に変えて、先ほどと同じように文字コードを出力してみます。

hello.html
<html>
  <head>
    <title>こんにちわ</title>
    <meta charset="UTF-8">
  </head>
  <body>
  </body>
</html>

実行結果

sample.rbの結果
$ ruby sample.rb
#<Encoding:ASCII-8BIT>
"UTF-8"

パース後の文字コードがUTF-8に変わっているのが確認できます。

ちなみにcharsetを無くしてみると、、、

hello.html
<html>
  <head>
    <title>こんにちわ</title>
    <meta>
  </head>
  <body>
  </body>
</html>
sample.rbの結果
$ ruby sample.rb
#<Encoding:ASCII-8BIT>
nil

パース後の文字コードがnilとなってしまいました。
もちろんこの状態でタイトル等を表示すると文字化けを起こします。

まとめ

  • htmlをバイナリで読み込み、かつNokogiriのエンコーディングをnilにすると、Nokogiriは自分で文字コードを参照しに行く
  • Nokogiriが参照しに行くのは、バイナリで読み込んだhtmlのmeta要素のcharset
  • charsetが書かれていないと、Nokogiriのエンコーディングはnilとなってしまう
0
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
0
0