java jsoup 乱码_告别中文乱码,自动检测网页编码的JAVA爬虫

麻烦的中文编码GB2312

写了个爬虫系统,结果运行没一会儿就发现队列里出现了乱码的url。检查发现网页是用gb2312编码的,我读取的时候是用utf8,所以中文就乱码了。原因找到了,开始fix。

一般而言,指定网页编码的地方有三处:

http header头部的Content-Type (Content-Type:text/html; charset=UTF-8)

源码 meta charset ()

源码 http-equiv ()

其中 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

47private 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);

}

/* 如果header里没有指定,从meta里找 */

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;

}

}

/* 如果都没有找到,默认使用UTF-8 */

if (charset == null || charset.isEmpty())

charset = "utf-8";

}

/* 用指定的编码来解析 */

html = new String(os.toByteArray(), charset);

}catch (Exception ex){

errMsg = ex.getMessage();

}

}

参考

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值