HTML::TreeBuilder::XPath+日本語で Wide character at lib/Encode.pm line 228.

特にjavascriptをONにしないでWeb上のHTMLをperlで解析・スクレイピングしたいときに、Wide character at C:/…./perl/lib/Encode.pm line 228.のようなエラーが出る時があります。その注意点があったので備忘録としてメモ。

使うモジュール

perlでスクレイピングしたいときは以下のようなモジュール使うと思います。

基本方針

で、基本的には以下の2点が重要。

  • プログラム外から入力したデータ(ファイルから読み込みとか、インターネットから取得したときなど)は、すべて Encode::decode(‘utf8’, $data); する。
  • プログラム内のデータを出力するとき(ファイルに書き込んだりコンソールに出力するなど)は、すべて Encode::encode(‘[出力先に合わせた文字コード]’, $data); する。

起こる問題

で、この基本通りにやると問題が無いのかというとそうでもない。

こんな感じでやると順調にいく場合もあるけど、たまーに「as_text」メソッドを呼んだときに「Wide character at [perlライブラリへのパス]Encode.pm line 228.」みたいなエラーが出て止まる。(泣)

原因と解決策

原因は、HTML::TreeBuilderのエスケープ処理が微妙で、日本語などに割り当てられている「&[アルファベット];」形式のHTMLエンティティが正しく処理できてないから。(…とか。英語圏の人が作ったモジュールにありがち…)

というわけで、解決方法としては初めにHTMLエンティティを削除するか、何か別の書式に直しておいて後で元に戻すのがいいと思う。

例えばこんな感じ。

独自の形式を何にするかは解析するhtmlの中に現れにくい(誤検出しにくい)形式がいいと思う。今回のようにアンダースコア2個(__)で挟んでもいいし、何か長くてランダムな文字列で挟むのもいいと思う。

まとめ

  • 外から入力した文字列はEncode::decode、外に出力するときはEncode::encode。
  • エンコードモジュールがエラーを出して止まってしまう時は、原因となっている文字を削除するか独自形式にして後で使う時に戻す。
  • 外国産のXMLパーサーでエラーが出るときも同様の点が問題になっている場合があるので同じように解決できる。

参考になれば幸いです。

カテゴリーperl

質問・コメントなどあればどうぞ