好久没写博客了,这段时间已经忙成狗,半年时间就这么没了,必须得做一下总结否则白忙。接下去可能会有一系列的总结,都是关于定向爬虫(干了好几个月后才知道这个名词)的构建方法,实现平台是Node.JS。

背景

一般爬虫的逻辑是这样的,给定一个初始链接,把该链接的网页下载保存,接着分析页面中的链接,找到目标链接检查是否已经请求过,如果未请求则放入请求队列,页面下载完成后交给索引器建立索引,如此往复即可建立一套提供给搜索引擎使用的文档库。我当时的需求并不是这样,而是抓取某几个网站的数据并把规定的字段输出为结构化的文件最终会放到EXCEL中分析。后者也许只需要该网站全量的商品数据,其它一概不需要,这样见面不需要保存。

我将顺着时间顺序记录问题和想法。

  1. 编码
  2. 重定向
  3. 并发

问题

编码遇到的第一个问题,也是在哪里都会遇到的问题,要彻底解决编码问题,就需要弄清楚三个问题:

  1. 为什么乱码?
  2. 如何找到内容的正确编码?
  3. 如何转码?

为什么乱码,当然是因为当前的字符串使用的编码并不是“正确”的,所谓“正确”就是该字符串在进入内存时用的什么编码去存储。举个粟子,“你”字的utf8编码[1]时内存的值:

这时候使用ascii来解码就得不到正确的文本,因为ascii最大也就认识7E[2]。之所以NodeJS打印非utf8的字符串乱码,是因为它默认使用utf8,所以必须要找到来源的正确编码转换成utf8。

那么如何找到内容的正确编码?看HTTP协议!在HTTP header中有一个Content-Type的field[3],它可以指定协议所支持的media-type,包括图片、文本、音频等,我们只看文本,并且是文本中的html,一般后面会跟上字符集编码。举个例子:

Content-Type: text/html; charset=ISO-8859-4

可以看到指定了html格式的文本类型和字符集,那当我们接收到返回时,只需要读取返回头中的Content-Type块,这就可以解决绝大部分问题了。但还没有完,有的网站并没有在HTTP header里面告诉你是什么字符集,例如:

Content-Type: text/html

baidu.com返回的就是这样的头,那浏览器如何知道怎么解析页面呢,因为浏览器打开并不会乱码,仔细看看返回的HTML文件就会发现文档里面会有meta标签来指定编[4]:

When the http-equiv attribute is specified on a meta element, the element is a pragma directive. You can use this element to simulate an HTTP response header, but only if the server doesn't send the corresponding real header; you can't override an HTTP header with a meta http-equiv element.

这样看来呢,协议头里面的优先级会高一点,所以正确的解析顺序是先从协议头中找编码方式,找不到再从文档里面寻找meta的http-equiv标签。(还有两篇文章关于UTF-8和Unicode详解写的很详细([5],[6]))。

找到了正确的编码以后,就可以找类库来做转码。比如从GBK编码转到UTF-8,只需要使用它们的编码对应关系做对应的替换。在NodeJS里面使用iconv和iconv-lite可以很好地完成这个工作,iconv是C++实现的本地库,安装会有些困难,iconv-lite是纯javascript实现的转码,安装相对简单,缺点是可能码不全也没有正式版。

多谢@落幕残情的提醒,再加一点补充。编码是可以通过检测来获取的,但是在WEB中并不是正确的做法,这种方法通常在不知道源的编码情况被迫使用的,而HTTP协议中和HTML文档规定了字符编码!检测概率模型存在误差,NodeJS有一个库叫做jschardet,该模块在node-webcrawler中被使用,实践告诉我出错概率非常大。再次感谢,欢迎其他想法。

[1]. http://zh.wikipedia.org/wiki/UTF-8

[2]. http://zh.wikipedia.org/wiki/ASCII

[3]. http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html

[4]. http://www.w3.org/wiki/HTML/Elements/meta

[5]. 关于文件编码格式的一点探讨

[6].Unicode详解

基于NodeJs的网页爬虫的构建(一)的更多相关文章

  1. 基于NodeJs的网页爬虫的构建(二)

    好久没写博客了,这段时间已经忙成狗,半年时间就这么没了,必须得做一下总结否则白忙.接下去可能会有一系列的总结,都是关于定向爬虫(干了好几个月后才知道这个名词)的构建方法,实现平台是Node.JS. 背 ...

  2. 一次使用NodeJS实现网页爬虫记

    前言 几个月之前,有同事找我要PHP CI框架写的OA系统.他跟我说,他需要学习PHP CI框架,我建议他学习大牛写的国产优秀框架QeePHP. 我上QeePHP官网,发现官方网站打不开了,GOOGL ...

  3. 基于nodeJS的小说爬虫实战

    背景与需求分析 最近迷恋于王者荣耀.斗鱼直播与B站吃播视频,中毒太深,下班之后无心看书. 为了摆脱现状,能习惯看书,我开始看小说了,然而小说网站广告多而烦,屌丝心态不愿充钱,于是想到了爬虫. 功能分析 ...

  4. nodeJS实现简单网页爬虫功能

    前面的话 本文将使用nodeJS实现一个简单的网页爬虫功能 网页源码 使用http.get()方法获取网页源码,以hao123网站的头条页面为例 http://tuijian.hao123.com/h ...

  5. 浏览器自动刷新——基于Nodejs的Gulp LiveReload与VisualStudio完美结合。

    本文版权桂博客园和作者吴双共同所有,转载和爬虫请注明原文地址 http://www.cnblogs.com/tdws/p/6016055.html 写在前面 大家好我是博客园的蜗牛,博客园的蜗牛就是我 ...

  6. Python 网页爬虫 & 文本处理 & 科学计算 & 机器学习 & 数据挖掘兵器谱(转)

    原文:http://www.52nlp.cn/python-网页爬虫-文本处理-科学计算-机器学习-数据挖掘 曾经因为NLTK的缘故开始学习Python,之后渐渐成为我工作中的第一辅助脚本语言,虽然开 ...

  7. [resource-]Python 网页爬虫 & 文本处理 & 科学计算 & 机器学习 & 数据挖掘兵器谱

    reference: http://www.52nlp.cn/python-%e7%bd%91%e9%a1%b5%e7%88%ac%e8%99%ab-%e6%96%87%e6%9c%ac%e5%a4% ...

  8. 【ShoppingWebCrawler】-基于Webkit内核的爬虫蜘蛛引擎概述

    写在开头 在各个电商平台发展日渐成熟的今天.很多时候,我们需要一些平台上的基础数据.比如:商品分类,分类下的商品详细,甚至业务订单数据.电商平台大多数提供了相应的业务接口.允许ISV接入,用来扩展自身 ...

  9. 【Python】Python 网页爬虫 & 文本处理 & 科学计算 & 机器学习 & 数据挖掘兵器谱

    本文转载自:https://www.cnblogs.com/colipso/p/4284510.html 好文 mark http://www.52nlp.cn/python-%E7%BD%91%E9 ...

随机推荐

  1. 局域网接入Internet

    说在前面的话 局域网接入Internet的方式多样: 有1传统的Modem(调制解调器)拨号接入,费用低廉的2 ISDN和 3 ADSL接入,费用较高的4 DDN专线接入,5 Cable Modem高 ...

  2. 字符串匹配之KMP算法

    KMP算法使用前缀函数来模拟有限自动机的后缀函数,前缀函数通过计算模式与其自身的偏移匹配的信息,本身的证明很复杂,关键在于弄懂其核心思想,下面就不赘述了,仅仅贴出代码: #include <io ...

  3. Java开源内容管理CMS系统J4CMS支持静态化直接ftp上传到你的空间了

    页面可直接编辑的cms系统j4cms能够直接支持使用ftp 输出 html到你的空间了 真正的静态化 这是静态化后的站点 http://www.j4cms.com/ 源代码上传至csdn了,能够下载源 ...

  4. Java中字符流与字节流的区别

    字符流处理的单元为2个字节的Unicode字符,分别操作字符.字符数组或字符串,而字节流处理单元为1个字节,操作字节和字节数组.所以字符流是由Java虚拟机将字节转化为2个字节的Unicode字符为单 ...

  5. dmesg 程序崩溃调试

    [root@localhost log]# cat -n /root/xx.c #include <stdio.h> void func(char *p) { *p = 'p'; } in ...

  6. cocos2dx shader

    http://www.oschina.net/question/565065_79818 Cocos2d-x 2.0 -- 从 点,线,面学起 http://blog.csdn.net/dawn_mo ...

  7. 嵌入式Linux-objdump命令的使用

    objdump命令的使用 objdump命令是Linux下的反汇编目标文件或者可执行文件的命令,它还有其他作用,下面以ELF格式可执行文件test为例详细介绍: objdump -f test 显示t ...

  8. [转]VS2010 (C#)winform程序打包发布图解

    1.新建一个Windows窗体应用程序,例如项目名为monitor,功能略.新建的时候不要忘了创建解决方案. 2.在monitor解决方案上“右击”—— “添加”——“新建项目”,选择“其他类型项目” ...

  9. UPDATE sql 优化

    一个网友说他的存储过程中有一段update sql,运行了15分钟还没出结果,需要优化一下 他把sql发给我 UPDATE TB_RESULT R SET R.VOTE_COUNT=NVL(( SEL ...

  10. 【Android】 onSaveInstanceState()恢复数据

    onSaveInstanceState()方法会携带一个 Bundle 类型的参数,Bundle 提供了一系列的方法用于保存数据,比如可以使用 putString()方法保存字符串,使用 putInt ...