转载: http://hi.baidu.com/erliang20088/item/9156132bdaeae8949c63d134

最近一个月一直在对nutch1.6版进行中等层次的二次开发,本来是想重新做一个自写的爬虫系统,鉴于前基做过微博爬虫系统,感觉再重写一个完整的爬虫费时、费力还没太大的含金量,故而直接基于nutch开发。

之所以说中是因为没有改动nutch的核心部分map/reduce,但改动了除此之外的绝大部分问题,最终形成了任务提交多样化、调度合理、数据流优化、乱码处理、源码与正文保存等较为合理的网络爬虫系统。经过处理之后,本爬虫可以采集中文、繁体、英文、藏文、俄文、日文、西里尔文等多种文字。现就网络爬虫中经常遇到的乱码问题,给予简要总结。

如果直接用nutch提供的web页面(nutch1.2版及之前是有自带的web展示系统,但之后的版本就没有了)就会很容易发现,总是会出现或多或少的页面。当深入源码后你会发现,nutch源码中对源网页中的编码的识别是很浅的,统一用utf-8来处理,没有做相关的编码的精准识别,只是留了相应的接口,供二次开发人员自行添加如cpdetector之类的基于统计的编码识别方式。

本系统的二次开发,主要采用截取nutch数据流的开始和结尾两部分数据来做,即提交数据、网页源码的数据两部分来做。网页通过阅读源码的网络IO代码会发现,http网页源码的流的读出是通过socket连接,得到其inputstream输入流之后,以字节流的方来来读的。

这里有个重点:如果源网页是GBK字节流,在程序端接收时的inputstream得到的字节数组的编码方式肯定是GBK字节流,即源网页是什么编码方式的字节流,程序端接收到的字节流的编码方式肯定是相同的。因此,只要在程序端解析出该流实际的编码方式即可将该流获得的源网页的字节数组转化成正常的编码显示形式。即算“解码--解析编码”的过程。

解析字节流的编码主要有三种方式,

一,通过http header中的content_type中的charset来获得,该编码是最准确的。

二,通过得到源网页的meta的charset来获得编码。

三,通过智能探测,如cpdetector,它是目前口碑最好的java实现的智能探测编码,是基于统计实现的,所以注定会有一定的错误率,经过我的实测,若干特殊网页,它确实是不准确的,如网页的meta中charset和实际的浏览器识别的正常显示的charset不相同的情况,它的识别也是错误的,所以最后我坚决没用它,而用了基于简单规则的方式,实际测试1000个种子网址证明,没发现任何乱码,除了一个站点它自身是乱码之外。

重点说下乱码的解决策略:

一、首先读取http header中的content_type的charset,如果有,则认定该charset是肯定准确的,直接做为解码的编码格式即可。

二、再按系统默认编码即UTF-8,去按行读取源网页中的meta和title的值,由于这两个值均为英文标签,所以在获取时肯定不会受到乱码的影响,故可以按UTF-8方式准确获取charset和title的值,此时的title有可能是乱码。

三、由于有不少中文站点中,虽然meta中的charset显示的是utf-8或是GBK,但实际的浏览器解析到的正常编码正好相反为gbk或是UTF-8,面对这种特例,而又发现只有在国内的站点会有如此情况,故做规则如下:

(1)首先判断此时的title若均为标点、字母、数字、中英文符号、GB18030的中文字符等,则认为此次的默认编码就是源网页的实际编码,而不管获得的charset是怎样的,并将charset设成为系统的默认编码utf-8。

(2)如果title满足第(1)条件,则用得到的charset去解码原始的字节流(如果charset就是utf-8,则省略后一步,直接将该charset作为实际的编码处理,即utf-8,原因在于很多俄文、西里尔文的标题多是UTF-8编码,但均不属于中文行列)。并获取新解析出来的源网页字符串的title。此时的新解码的charset即为最终的源网页认定的charset。

解码完成后,在保存源网页的实际数据时,先对得到的原始字节数组按上一步得到的charset解码,即:

String source_webpage_string=new String(original_byte_array,charset);

此时得到的source_webpage_string即为正常的源网页中,再进行重编码:

new_byte_array=source_webpage_string.getBytes(system.defaultEncoding);//即utf-8

再用utf-8对正常的串进行编码,得到统一编码下的字节数组,通过java io写入到即定的大文件中即可。

当然如果charset值就是默认的utf-8,则无需解码,直接存储即可。

有人会问为何要先解码?答案是:解码是为了统一编码。做为爬虫系统,会有来自成千上万个站点的网页存储到系统中,而网页的编码有很多,像GBK、Unicode、big5、shift-js、windows-1521等等,如果直接存储而不统一编码在应用端读取的时候,就要读出字节数组后按原始的编码解析才能得到非乱码显示,到视图端显示的时候也要如此转化,显然这样做是不合理的,而应该是在爬取下来存储的时候,都统一存成UTF-8编码的即可,统一之后,无论哪一端来读,都可以直接按UTF-8来处理。这也是统用、主流做法。

经过如上的处理,各个国家的站点出现乱码的概率几乎为0,本人的实际测试情况亦是如此。

希望对正在学习网络爬虫的同学们有帮助。

crawler_网络爬虫中编码的正确处理与乱码的解决策略的更多相关文章

  1. 网络爬虫中Fiddler抓取PC端网页数据包与手机端APP数据包

    1 引言 在编写网络爬虫时,第一步(也是极为关键一步)就是对网络的请求(request)和回复(response)进行分析,寻找其中的规律,然后才能通过网络爬虫进行模拟.浏览器大多也自带有调试工具可以 ...

  2. crawler_网络爬虫之数据分析_httpwatcher

    所谓爬虫,首先要通过各种手段爬取到想要站点的数据. web2.0之后,各种网络站点类型越来越多,早期的站点多为静态页面[html .htm],后来逐步加入 jsp.asp,等交互性强的页面.再后来随着 ...

  3. Java中读取txt文件中中文字符时,出现乱码的解决办法

    这是我写的一个Java课程作业时,遇到的问题. 问题描述: 我要实现的就是将txt文件中的内容按一定格式读取出来后,存放在相应的数组. 我刚开始运行时发现,英文可以实现,但是中文字符就是各种乱码. 最 ...

  4. ubuntu14.04中解压缩window中的zip文件,文件名乱码的解决方法

    在windows上压缩的文件,是以系统默认编码中文来压缩文件.由于zip文件中没有声明其编码,所以linux上的unzip一般以默认编码解压,中文文件名会出现乱码. 通过unzip行命令解压,指定字符 ...

  5. C#中StreamReader读取中文文本出现乱码的解决方法

    在编写文本文件读写程序的过程中,有如下代码 StreamReader sr = new StreamReader(FileName); 结果发现打开中文文本文件出现乱码. 究其原因,原来自从Windo ...

  6. 【已解决】关于IDEA中 Tomcat 控制台打印日志中文乱码的解决

    在 Idea 上面使用 Tomcat 时,发现控制台打印信息的时候,出行中文乱码问题; 可以通过以下几种解决办法 1:在-Dfile.encoding=UTF-8 在vm中设置编码方式 2.然后从Fi ...

  7. [转]IE、FireFox、Chrome浏览器中关于URL传参中文乱码,解决兼容性问题!

    原文地址:https://cloud.tencent.com/developer/article/1334736 前台用url传值中文,后台用request.getParameter接收参数.在Fir ...

  8. JDBC中向数据库录入汉字产生乱码的解决办法

    在近期的课程设计中遇到在eclipse中向数据库中录入数据,产生的汉字乱码现象,在这里提供一条解决的方法: 只需连接地址URL中数据库名后面添加“?characterEncoding=utf-8”即可 ...

  9. win7系统中使用DOS命令是出现乱码的解决方法

    方法一:设置cmd显示字体1.win+R打开运行窗口->输入cmd->回车,打开命令行提示符窗口 win7系统运行窗口win7系统DOS命令行提示窗口 2.在命令行标题栏上点击右键,选择” ...

随机推荐

  1. CF417D--- Cunning Gena(序列+像缩进dp)

    A boy named Gena really wants to get to the "Russian Code Cup" finals, or at least get a t ...

  2. SorlNet

    Solr学习 上一篇已经讲到了Solr 查询的相关的参数.这里在讲讲C#是如何通过客户端请求和接受solr服务器的数据, 这里推荐使用SolrNet,主要是:SolrNet使用非常方便,而且用户众多, ...

  3. c# winform 中的 工具栏自动隐藏 splitter用法 带源码

    c# winform 中的 工具栏自动隐藏 splitter用法 带源码 代码下载地址 http://download.csdn.net/detail/simadi/7649313

  4. [原创].NET 分布式架构开发实战之四 构建从理想和实现之间的桥梁(前篇)

    原文:[原创].NET 分布式架构开发实战之四 构建从理想和实现之间的桥梁(前篇) .NET 分布式架构开发实战之四 构建从理想和实现之间的桥梁(前篇) 前言:上一篇文章讲述了一些实现DAL的理论,本 ...

  5. 深入研究Java类载入机制

    深入研究Java类载入机制   类载入是Java程序运行的第一步,研究类的载入有助于了解JVM运行过程,并指导开发人员採取更有效的措施配合程序运行. 研究类载入机制的第二个目的是让程序能动态的控制类载 ...

  6. iostream与iostream.h乱弹琴

    #include <iostream.h> 非标准输出流 #include <iostream>    标准输出流 见短eclipse关于使用android ndk时的简单代码 ...

  7. .NET应用架构设计—再次了解分层架构(现代企业应用分层架构核心设计元素)

    阅读文件夹: 1.背景介绍 2.简要回想下传统三层架构 3.企业级应用分层架构(现代分层架构的基本演变过程) 3.1.服务层中应用契约式设计来解决动态条件不匹配错误(通过契约式设计模式来将问题在线下暴 ...

  8. Cocos2d-X中实现批处理精灵

    使用普通方法实现批处理精灵 在Sprite.h中加入以下的代码 #ifndef __Sprite_SCENE_H__ #define __Sprite_SCENE_H__ #include " ...

  9. Spring 的@Scheduled注解实现定时任务运行和调度

    Spring 的@Scheduled注解实现定时任务运行和调度 首先要配置我们的spring.xml   ---  即spring的主配置文件(有的项目中叫做applicationContext.xm ...

  10. 【2014】【】辛星【php】【秋】【1】php构建开发环境

    **************************什么是开发环境*********************** 1.我们学习PHP,是使用它来做web用的,通俗理解,就是做站点. 2.站点的执行须要 ...