crawler_网络爬虫中编码的正确处理与乱码的解决策略
转载: 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_网络爬虫中编码的正确处理与乱码的解决策略的更多相关文章
- 网络爬虫中Fiddler抓取PC端网页数据包与手机端APP数据包
1 引言 在编写网络爬虫时,第一步(也是极为关键一步)就是对网络的请求(request)和回复(response)进行分析,寻找其中的规律,然后才能通过网络爬虫进行模拟.浏览器大多也自带有调试工具可以 ...
- crawler_网络爬虫之数据分析_httpwatcher
所谓爬虫,首先要通过各种手段爬取到想要站点的数据. web2.0之后,各种网络站点类型越来越多,早期的站点多为静态页面[html .htm],后来逐步加入 jsp.asp,等交互性强的页面.再后来随着 ...
- Java中读取txt文件中中文字符时,出现乱码的解决办法
这是我写的一个Java课程作业时,遇到的问题. 问题描述: 我要实现的就是将txt文件中的内容按一定格式读取出来后,存放在相应的数组. 我刚开始运行时发现,英文可以实现,但是中文字符就是各种乱码. 最 ...
- ubuntu14.04中解压缩window中的zip文件,文件名乱码的解决方法
在windows上压缩的文件,是以系统默认编码中文来压缩文件.由于zip文件中没有声明其编码,所以linux上的unzip一般以默认编码解压,中文文件名会出现乱码. 通过unzip行命令解压,指定字符 ...
- C#中StreamReader读取中文文本出现乱码的解决方法
在编写文本文件读写程序的过程中,有如下代码 StreamReader sr = new StreamReader(FileName); 结果发现打开中文文本文件出现乱码. 究其原因,原来自从Windo ...
- 【已解决】关于IDEA中 Tomcat 控制台打印日志中文乱码的解决
在 Idea 上面使用 Tomcat 时,发现控制台打印信息的时候,出行中文乱码问题; 可以通过以下几种解决办法 1:在-Dfile.encoding=UTF-8 在vm中设置编码方式 2.然后从Fi ...
- [转]IE、FireFox、Chrome浏览器中关于URL传参中文乱码,解决兼容性问题!
原文地址:https://cloud.tencent.com/developer/article/1334736 前台用url传值中文,后台用request.getParameter接收参数.在Fir ...
- JDBC中向数据库录入汉字产生乱码的解决办法
在近期的课程设计中遇到在eclipse中向数据库中录入数据,产生的汉字乱码现象,在这里提供一条解决的方法: 只需连接地址URL中数据库名后面添加“?characterEncoding=utf-8”即可 ...
- win7系统中使用DOS命令是出现乱码的解决方法
方法一:设置cmd显示字体1.win+R打开运行窗口->输入cmd->回车,打开命令行提示符窗口 win7系统运行窗口win7系统DOS命令行提示窗口 2.在命令行标题栏上点击右键,选择” ...
随机推荐
- C++习题 对象数组求最大值
Description 建立一个对象数组,内放n(<10)个学生的数据(学号.成绩),设立一个函数max,用指向对象的指针作函数参数,在max函数中找出n个学生中成绩最高者,并输出其学号. In ...
- iOS 中client和server的 Web Service 网络通信 (2)
在实际的应用开发过程中,同步请求的用户体验并非非常好:我们都知道.Apple是非常重视用户体验的.这一点也成为了行业的标杆,没实用户哪里来的好产品.所以用户体验是极其重要的.貌似废话有点多.接下来进入 ...
- perl操作sqlserver实现BCP
#!C:\Perl64\bin #由BCP备份和恢复SQLSERVER指定表 use 5.014; #加载用户和password型材 my $username ; my $passwd; ##得到us ...
- STL源代码剖析(一) - 内存分配
Allocaor allocator 指的是空间配置器,用于分配内存.STL中默认使用SGI STL alloc作为STL的内存分配器,尽管未能符合标准规格,但效率上更好.SGI STL也定义有一个符 ...
- Redis源代码分析(23)--- CRC循环冗余算法RAND随机数的算法
他今天就开始学习Redis源代码的一些工具来实现,在任何一种语言工具.算法实现的原理应该是相同的,一些比較经典的算法.比方说我今天看的Crc循环冗余校验算法和rand随机数产生算法. CRC算法全称循 ...
- java.io.NotSerializableException
结果发现序列不成功非静态内部类时的序列中,出现以下异常: java.io.NotSerializableException: com.tang.sharedpreferencesdemo.MainAc ...
- 百度云BAE3.0 的ssh构造(本机ssh项目迁移到BAE3.0)
依据百度云的java部署文档进行部署 http://developer.baidu.com/wiki/index.php?title=docs/cplat/bae/java 做例如以下改动,然后把项目 ...
- Android Property Animation 物业动画
效果图: Property Animation介绍: 出生在sdk3.0,是利用了View所拥有的属性,进行一系列的操作. 比方一个View有什么样的setAbc的属性,那么理论上就能够设置它. ...
- 12本最优秀的Android开发电子书强力推荐
如今已经是手机互联网时代,手机应用越来越普及.Android作为基本的手机操作系统.吸引了众多开发人员開始为Android系统开发应用. 假设你正在开发或者准备进行Android的开发,我们今天推荐的 ...
- HDU 3874 离线段树
在所有数字的统计范围,,对于重复统计只有一次 离线段树算法 排序终点坐标.然后再扫,反复交锋.把之前插入树行被删除 #include "stdio.h" #include &quo ...