Nutch1.8在使用默认网页解析插件解析网页文本时,有些网页会出现在乱码问题。
出现乱码的原因分析:
parse-html插件在解析网页文本时,会先使用正则表达匹配出网页的编码。源码如下
(文件路径:NUTCH_HOME/src/plugin/parse-html/src/java/org/apache/nutch/parse/html/HtmlParser.java):
private static Pattern metaPattern = Pattern.compile("<meta\\s+([^>]*http-equiv=(\"|')?content-type(\"|')?[^>]*)>", Pattern.CASE_INSENSITIVE); private static Pattern charsetPattern = Pattern.compile("charset=\\s*([a-z][_\\-0-9a-z]*)", Pattern.CASE_INSENSITIVE);
该正则表达式只能匹配出使用<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />标明网页编码的网页。国内有些网站是使用<meta charset="utf-8" />来标明网页编码,因此插件无法解析出网页的编程。当无法解析出网页编码时,插件会使用nutch配置文件设置的默认解析编码。如果没有在nutch-site.xml文件中配置默认解析网页的编码,程序会使用nutch-default.xml文件的默认配置。默认配置如下:
(文件路径:NUTCH_HOME/conf/nutch-default.xml)
<property> <name>parser.character.encoding.default</name> <value>windows-1252</value> <description>The character encoding to fall back to when no other information is available</description> </property>
默认编码是windows-1252,针对没有提取出网页编码的网页,解析出来的网页内容就是乱码了。
解决方法:
1、 在原来匹配基础上增加正则匹配规则,匹配使用<meta charset="utf-8" />标明网页编码的网站,正则表达式是:
private static Pattern metaPatternOther = Pattern.compile("<meta\\s+([^>]*charset=\\s*(\"|')?\\s*([a-z][_\\-0-9a-z]*)(\"|')?[^ >]*)>", Pattern.CASE_INSENSITIVE);
private static Pattern charsetPatternOther = Pattern.compile("charset=\\s*((\"|')?([a-z][_\\-0-9a-z]*)(\"|')?)", Pattern.CASE_INSENSITIVE);
private static Pattern charsetPatternAnother = Pattern.compile("charset\\s*=\\s*((\"|')?([a-z][_\\-0-9a-z]*)(\"|')?)", Pattern.CASE_INSENSITIVE);
2、 修改nutch-site.xml配置文件,设置默认解析网页的编码为utf-8或者gb2312,我这里设置的是ut8-8。Nutch会使用配置的默认编码解析网页,对于中文网站来说,主要是这两种编码。
<property> <name>parser.character.encoding.default</name> <value>utf-8</value> <description>The character encoding to fall back to when no other information is available</description> </property>
经过这样处理,解析爬取的网页大部分乱码被解决掉了。我使用nutch版本是1.8,其它版本不知道也是如此否,可以自行测试。
余留问题
还有一些乱码没解决,经过分析,都是繁体字的乱码,而且当转为utf-8时,报错信息是utf-8的编码长度不够。Big5是繁体中文de facto标准,所以这个错误的大概意思就是说utf-8编码一个汉字的字节要比Big5小。由于我们解析网页编码格式时只会分析网页源代码中的“charset”属性的值作为网页编码格式,Big5貌似不作为这个属性值出现(反正我暂时还没见过这种情况),这样繁体就解析不出来了,就成乱码了。(关于这个问题我暂时是这么理解的,慢慢研究吧~~~,欢迎交流探讨!)
附录
Big5:这是繁体中文 de facto 标准。 CNS11643:台湾的官方标准繁体中文编码。 Cp937:繁体中文加上 6204 个使用者自定的字符 Cp948:繁体中文版 IBM OS/2 用的编码方式。 Cp964:繁体中文版 IBM AIX 用的编码方式。 EUC_TW:台湾的加强版 Unicode。 ISO2022CN:编码中文的一套标准。 ISO2022CN_CNS:编码中文的一套标准,繁体版,袭自 CNS11643。 MS950 或 Cp950:ASCII + Big5,用于台湾和香港的繁体中文 MS Windows操作系统。 Unicode:有次序记号的 Unicode。次序记号占用两个 byte,如果其值是0xFEFF,表示使用 big-endian(由大到小)的次序为 Unicode 编码;如果其值是 0xFFFF,表示使用 little-endian(由小到大)的次序为 Unicode 编码。 UnicodeBig:使用 big-endian(由大到小)的次序为 Unicode 编码。 UnicodeLittle:使用 little-endian(由小到大)的次序为 Unicode 编码。 UTF8:使用 UTF-8 为 Unicode 编码。