M.C.P.C.

―むり・くり―プラスコミュニケーション(更新終了)


| トップページ |

2011年3月27日 00:00

WWW::MechanizeやWeb::Scraperはmetaタグを見てデコードするが、charset=Shift_JISのコンテンツって実際にはCP932なので化けるのを防ぐEncode::Alias

このエントリーをはてなブックマークに追加 mixiチェック

WWW::MechanizeというPerlのウェブブラウザになりきるモジュールで、2006年9月の、バージョン1.21_01から、自動的にHTML文書のmetaタグなどからエンコーディングを取得して、デコードしてくれるのだけれども、オンライン上にあるほとんどのShift_JIS指定のHTML文書のほとんどが実際にはCP932(シフトJISのMicrosoft拡張)になっているために、文字化けしちゃうっていう問題があって、どうすれバインダー(未解決)っていうのを以前やりました。

M.C.P.C.: WWW::Mechanizeはmetaタグを見てデコードするが、charset=Shift_JISのコンテンツって実際にはCP932なので化けるじゃねえか問題

んで、おととい、東北電力の計画停電予定を公表するページのHTMLをYAMLに変換するやつを作ったのですけれども、

M.C.P.C.: 東北電力の計画停電予定告知ページのHTMLからYAMLに変換するPerlスクリプト

その際利用した、Web::Scraperでも同じ問題があったので、ちょっと調べてみたら、解決する方法を見つけました。

問題は、HTML文書がCP932で規定された範囲の文字(髙橋の「髙」、山﨑の「﨑」など)が使われているのに、metaタグでは、<meta http-equiv="content-type" content="text/html; charset=Shift_JIS">とかしなくちゃいけないので、metaタグを真面目に参照すると、文字化けが起こるっていうことです。

これを解決するには、

cp932 vs. shift_jis - Bulknews::Subtech - subtech [g.hatena.ne.jp]

この手の話はよくみるけど、cp932 のほうがうれしいということであれば単純に

use Encode::Alias;
define_alias( qr/shift.*jis$/i  => '"cp932"' );
define_alias( qr/sjis$/i        => '"cp932"' );

としてShift_JISを cp932 のエイリアスにしちゃえばいいんじゃないのかなあ? ていうかこの例は perldoc Encode::Alias にでてくる。

ということで、Encode::Aliasを使って、他の場所でShift_JISをエンコーディングに指定しても、実際にはCP932を指定している、ということにしてしまえばいいのですね。

こうなります。

Filename: sjis.html(シフトJISで保存)

<html>
  <head>
    <meta http-equiv="content-type" content="text/html; charset=Shift_JIS" />
    <title>髙橋~山﨑 テスト</title>
  </head>
  <body>
    <p>髙橋</p>
    <p>~</p>
    <p>山﨑</p>
  </body>
</html>

これを、前回のコード

use strict;
use warnings;
use utf8;
use WWW::Mechanize;
binmode STDOUT => ':utf8';
 
my $mech = WWW::Mechanize->new();
$mech->agent('Windows IE 6'); 
$mech->get('http://www.example.com/sjis.html');
print $mech->content();
 
exit;
 
__END__

で取得すると……

$ perl sjis.pl
<html>
  <head>
    <meta http-equiv="content-type" content="text/html; charset=Shift_JIS" />
    <title>��橋〜山�ア テスト</title>
  </head>
  <body>
    <p>��橋</p>
    <p>〜</p>
    <p>山�ア</p>
  </body>
</html>$

となってしまうのですが、

こういうコード

use strict;
use warnings;
use utf8;
use WWW::Mechanize;
binmode STDOUT => ':utf8';
use Encode::Alias;
define_alias( qr/shift.*jis$/i  => '"cp932"' );
define_alias( qr/sjis$/i        => '"cp932"' );
  
my $mech = WWW::Mechanize->new();
$mech->agent('Windows IE 6'); 
$mech->get('http://www.example.com/sjis.html');
print $mech->content();
 
exit;
 
__END__

で取得すると、

$ perl sjis.pl
<html>
  <head>
    <meta http-equiv="content-type" content="text/html; charset=Shift_JIS" />
    <title>髙橋~山﨑 テスト</title>
  </head>
  <body>
    <p>髙橋</p>
    <p>~</p>
    <p>山﨑</p>
  </body>
</html>
$

と平気です。

Encode::Aliasは、Shift_JIS(実際にはCP932)のHTMLをマニピュレートしなくてはいけない場合に必須っぽいですね!

投稿 大野 義貴 [Perl] | |

トラックバック(0)

トラックバックURL: http://blog.dtpwiki.jp/MTOS/mt-tb.cgi/3538

コメントする