Nokogiri で encoding error
以下のファイルを Nokogiri で解析させるとエラー。
- demo-1.html
<?xml version="1.0" encoding="euc-jp"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html lang="ja" xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja"> <head> <meta name="keywords" content="ロ" /> <meta http-equiv="Content-Type" content="text/html; charset=EUC-JP" /> </head> <body> テスト </body> </html>
- ex-1.rb
require 'rubygems' require 'nokogiri' require 'open-uri' doc = Nokogiri(open(ARGV[0])) puts doc.to_html
実行
$ ruby ex-1.rb demo-1.html |iconv -f euc-jp -t utf-8 encoding error : output conversion failed due to conv error, bytes 0x95 0x24 0xC8 0x26 I/O error : encoder error
http://d.hatena.ne.jp/kitamomonga/20100712/ruby_mechanize_loses_to_euc_html_tips
を読むと、meta charset の前にマルチバイト文字(特定の文字。上の例では
meta keywords に カタカナの"ロ")が 書かれている場合に起きる。
demo-1.html を、charset の後にマルチバイト文字が来るように書き換えると
- demo-2.html(抜粋)
<head> <meta http-equiv="Content-Type" content="text/html; charset=EUC-JP" /> <meta name="keywords" content="ロ" /> </head>
実行
$ ruby ex-1.rb demo-2.html |iconv -f euc-jp -t utf-8 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <?xml version="1.0" encoding="euc-jp"?><html lang="ja" xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja"> <head> <meta http-equiv="Content-Type" content="text/html; charset=EUC-JP"> <meta name="keywords" content="ロ"> </head> <body> テスト </body> </html>
無事 出力される。
とは言え、世に公開されている膨大な HTML を手動で書き換えるわけには
いかないので、プログラムで対処する。
- ex-2.rb
require 'rubygems' require 'nokogiri' require 'open-uri' require 'kconv' str = open(ARGV[0]).read noko_en_id = { Kconv::UTF8 => 'UTF-8', Kconv::EUC => 'EUC-JP', Kconv::SJIS => 'SHIFT-JIS', Kconv::ASCII => 'ASCII', Kconv::JIS => 'ISO-2022-JP', # Kconv::UTF16 => , # Kconv::UNKNOWN => , }[Kconv.guess(str)] || raise doc = Nokogiri::HTML.parse(str, nil, noko_en_id) puts doc.to_html
実行
$ ruby ex-2.rb demo-1.html |iconv -f euc-jp -t utf-8 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <?xml version="1.0" encoding="euc-jp"?><html lang="ja" xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja"> <head> <meta name="keywords" content="ロ"> <meta http-equiv="Content-Type" content="text/html; charset=EUC-JP"> </head> <body> テスト </body> </html>
無事出力される。二度手間感は否めないが