解决Perl 5.8.8用XML::RSS无法解析非utf-8编码的RSS问题
摘要:XML-RSS-1.36是 常用的操作RSS的模块,不过遗憾的是,不支持gb2312,big5等编码的rss文件,操作的话直接报错“Couldn't open encmap gb2312.enc”退出。今天一段代码读baidu的新闻rss 时遇到这个问题,先鄙视一下他用gb2312编码。网上搜索到的解决方案在我这里无效,最终自己比较不优雅的解决了一下。
这个问题发生的原因是XML::RSS模块会调用XML::Parser模块,最终是调用的Perl的核心库Expat,这东西是C写的,不支持gb2312编码。网上搜索到的解决办法如下:
1. Download GB2312.TXT from ftp.unicode.org,事实上这个东西目前下载地址是http://search.cpan.org/src/GUS/Unicode-UTF8simple-1.06/gb2312.txt
2. Download the XML::Encoding 1.01 and get two binaries: make_encmap and compile_encoding,这东西在d:\perl\bin下面,根据的安装目录而有变化。
3. run make_encmap as follows:make_encmap GB2312 GB2312.TXT > GB2312.encmap
4. Add expat='yes' to the first line of GB2312.encmap
5. run compile_encoding: compile_encoding -o GB2312.enc GB2312.encmap
6. copy GB2312.enc to /usr/lib/perl5/site_perl/5.005/i386-linux/XML/Parser/Encoding,windows的话,lib/下面自己去找。
不过遗憾的是,现在这种方法已经不行了,最后在<<Thinking in perl>>中找到原因,如下:
使用 make_enmap 的时候需要改下载来的GB2312.TXT。因为在 GB2312.txt 中,中文编码0x2121 的应该为 0xa1a1 , 即第一列值全部需要加 0x8080,这样就可以了。修改 make_enmap给需要处理的地方每个值加 0x80。
不过这样还是太麻烦了,我的做法是直接给XML文件编码一下,代码片段如下:
-
$xml = get( 'http://news.baidu.com/n?cmd=1&class=internet&tn=rss⊂=0' );
-
if( ! defined($xml) )
-
{
-
warn "$!n";
-
return;
-
}
-
if( $xml =~ /s+encoding="(.*?)"/ )
-
{
-
$encode = $1;
-
}
-
if ( &trim($encode) eq "" )
-
{
-
print "No encode found, use utf-8.n";
-
}
-
if( ($encode ne "") && ($encode ne "utf-8") && ($encode ne "UTF-8") )
-
{
-
$xml = decode_utf8( decode( $encode, $xml ) );
-
}
-
$xml =~ s/encoding="(.*?)"/encoding="utf-8"/;
-
my $rss = new XML::RSS;
-
$rss->parse($xml);
先抓取RSS数据,然后查询编码,不是utf-8的话,自己解码再编码到utf-8,并且记得要替换xml文件中的编码申明。