麻烦的中文编码GB2312
写了个爬虫系统,结果运行没一会儿就发现队列里出现了乱码的url。检查发现网页是用gb2312编码的,我读取的时候是用utf8,所以中文就乱码了。原因找到了,开始fix。
一般而言,指定网页编码的地方有三处:
- http header头部的Content-Type (
Content-Type:text/html; charset=UTF-8
)
- 源码 meta charset (
<meta charset="UTF-8"/>
)
- 源码 http-equiv (
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
)
其中 http header是服务器指定的,优先级最高,剩下两个一般不会同时出现,顺序无所谓。
策略是,先把网页下载下来,然后依次找上述三个位置,找到编码就用该编码将字符串以该编码转换成utf8,但是实际测试发现,不管怎么转都是乱码,最好的情况下确实转成了中文,但是跟原来完全不是同一个字啊。例如 “校内办公――电子地图” 变成了 “校锟节办公锟斤拷锟斤拷锟斤拷锟接碉拷图”。
网上找到的关于java编码的问题都是说需要在读取的时候指定编码,不然就会产生中文乱码。然而,我这是爬虫,在下载之前我并不知道它用的是什么编码啊。
思来想去,无论什么编码,英文字符显示都是正常的,可以用字节流先以字节的形式把网页存下来;然后转成字符串获得编码;最后再利用正确的编码对原字节数组进行编码转换。
示例代码
核心代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| private void parse(HttpEntity entity){ ContentType contentType = ContentType.get(entity); Charset cs = contentType.getCharset(); if (cs != null) { charset = cs.toString(); logger.info("Detect charset in header:"+charset); }
try { InputStream is = entity.getContent(); ByteArrayOutputStream os = new ByteArrayOutputStream(1024); byte[] temp = new byte[1024]; int size; while ((size = is.read(temp)) != -1) { os.write(temp, 0, size); } if (charset == null) { Document doc = Jsoup.parse(os.toString()); Elements metaTags = doc.getElementsByTag("meta"); for (Element metaTag : metaTags) { String content = metaTag.attr("content"); String http_equiv = metaTag.attr("http-equiv"); charset = metaTag.attr("charset"); if (!charset.isEmpty()) { logger.info("Detect charset in meta:"+charset); break; } if (http_equiv.toLowerCase().equals("content-type")) { charset = content.substring(content.toLowerCase().indexOf("charset") + "charset=".length()); logger.info("Detect charset in http-equiv:"+charset); break; } } if (charset == null || charset.isEmpty()) charset = "utf-8"; } html = new String(os.toByteArray(), charset); }catch (Exception ex){ errMsg = ex.getMessage(); } }
|
完整代码见:CRSpider.java
参考
HTML5标准学习 – 编码
Java获取网页编码
Cpdetector识别网页编码 解决Java爬虫乱码问题
java中文乱码解决之道(五)—–java是如何编码解码的
HttpClient 4.0的使用详解
java中GBK编码格式转成UTF8,用一段方法实现怎么做?