使用NodeJs,实现数据抓取

学习笔记

前言

近期做一个数据抓爬工具,最开始使用的是C#控制台应用,同时正则表达式去过滤数据,看着还行,可每次运行都依附于.net framework很是不爽,于是想整点其他的方法。本人还是比较喜欢javascript的,思来想去决定用服务器端的javascript来试试!

环境、工具准备

1、[必装] 安装nodejs,下载最新nodejs,点击此处

2、[选装] 安装iisnode,以及rewrite,因为我是以IIS作为Server,所以用到了这2个IIS的拓展插件,假如仅仅只是cmd控制台运行node则这第二项忽略

3、附加信息:当安装成功之后,在IIS下回出现URL重写这么个东东

  

范例实现

我以一个小小的案例来实现这么个功能,咱们去抓下面这个站点的数据测试一下:http://www.jj59.com/

1、抓列表,http://www.jj59.com/jingpinwenzhang/list_68_3.html

2、抓详情,http://www.jj59.com/jingpinwenzhang/082919.html

原网站截图如下:

接下来我要做的就是

1、将指定页的列表页中文章的标题与对应链接过滤出来,然后返回json数组

2、将详情页文章标题,作者,创建时间,内容过滤出来,然后返回json对象

具体nodejs代码于运行结果

 1 var http = require(‘http‘);
 2 var _url = require(‘url‘);    //引用url模块,处理url地址相关操作
 3 var cheerio = require("cheerio");    //引用cheerio模块,使在服务器端像在客户端上操作DOM,不用正则表达式
 4 var iconv = require(‘iconv-lite‘);    //解决编码转换模块
 5 var BufferHelper = require(‘bufferhelper‘);    //关于Buffer我后面细说
 6 /*
 7  *最后我需要达到的效果是,给予一个访问地址,形如:http://www.mynode.com?link=www.abc.com&callback=cb
 8  *我希望可以返回json,也可返回jsonp
 9 */
10
11 http.createServer(function (req, res) {
12     var arg = _url.parse(req.url, true).query;    //通过调用url模块,获取查询字符串参数集合
13     var link = arg.link;    //获取抓取的link
14     var callback = arg.callback;    //回调函数的名称
15     //若没有对link加上http,则补全
16     var protocol = "http";
17     if (link.indexOf("http") < 0) {
18         link = protocol + "://" + link;
19     }
20     //抓取页面
21     download(link, function (data) {
22         res.writeHead(200, {
23             "Content-Type": "text/html;charset=utf-8",
24             "Transfer-Encoding": "chunked"
25         });
26         var doc = data.toString();
27         var $ = cheerio.load(doc);
28         var list = [];
29         $(".e2 li .title").each(function (i, e) {
30             var item = $(e).children("a").last();
31             var title = item.text();
32             var link = item.attr("href");
33             list.push({ "title": title, "link": link });
34         });
35         var jsonText = JSON.stringify(list);
36         if (callback) {
37             res.write(callback + "(" + jsonText + ")");
38         }
39         else {
40             res.write(jsonText);
41         }
42         res.end();
43     });
44 }).listen(process.env.PORT);
45
46 //加载第三方页面
47 function download(url, callback) {
48     http.get(url, function (res) {
49         var bufferHelper = new BufferHelper();    //解决中文编码问题
50         res.on(‘data‘, function (chunk) {
51             bufferHelper.concat(chunk);
52         });
53         res.on("end", function () {
54             //注意,此编码必须与抓取页面的编码一致,否则会出现乱码,也可以动态去识别
55             var val = iconv.decode(bufferHelper.toBuffer(), ‘gb2312‘);
56             callback(val);
57         });
58     }).on("error", function () {
59         callback(null);
60     });
61 }

1、列表页json列表

请求的url:http://myurl?link=http://www.jj59.com/jingpinwenzhang/list_68_3.html&callback=cb

cb([{"title":"流金岁月 书香伴行","link":"http://www.jj59.com/jingpinwenzhang/096929.html"},{"title":"奋斗书写无悔青春","link":"http://www.jj59.com/jingdianmeiwen/088963.html"},{"title":"如果他喜欢你,就不会暧昧不清;如果他不再联系你,别为他找理由","link":"http://www.jj59.com/jingpinwenzhang/082919.html"},{"title":"月下彷徨,你已不复当年模样","link":"http://www.jj59.com/jingdianmeiwen/082295.html"},{"title":"话糙理不糙的农家话(4)","link":"http://www.jj59.com/jingpinwenzhang/080410.html"},{"title":"浮生若梦,掩袖一笑弹指间","link":"http://www.jj59.com/jingdianmeiwen/078491.html"},{"title":"转瞬柔,似是非","link":"http://www.jj59.com/jingpinwenzhang/078002.html"},{"title":"春天","link":"http://www.jj59.com/jingdianmeiwen/077439.html"},{"title":"当生活的“美”成为一种遗憾","link":"http://www.jj59.com/jingdianmeiwen/074365.html"},{"title":"中秋节的起源、食俗、古诗佳句","link":"http://www.jj59.com/jingpinwenzhang/043440.html"}])

2、详情页json对象

请求的url:http://myurl?link=http://www.jj59.com/jingpinwenzhang/082919.html&callback=cb

cb({"title":"如果他喜欢你,就不会暧昧不清;如果他不再联系你,别为他找理由","date":"2011-05-12","auth":"午夜未殇","content":"  1、如果他被动矜持。\r\n  \r\n  “也许他不想破坏我们的友谊”\r\n  \r\n  “也许他害羞”“也许他自卑”\r\n  \r\n  “也许他只是不知道怎么联络我”……\r\n  \r\n  Gerg说,在整个人类历史进程中,\r\n  \r\n  任何一个男的都会为了接近你而不在乎断送“友情”,\r\n  \r\n  他也不可能因为害羞和自卑而害怕得不敢追你,\r\n  \r\n  他唯一“害怕”的只是他对你是那么的“无动于衷”,\r\n  \r\n  他不会不知道怎么联络你,手机,email,IM,SNS,twitter……\r\n  \r\n  他可以动用他的眼睛、嘴巴、大脑、关系网、google找到你——除非他不想找到你。\r\n  \r\n  也许有人提倡这已经不是石器时代了,\r\n  \r\n  女孩子去主动追求看上的人吧,\r\n  \r\n  但是相信真正喜欢你的人一定不会让你费尽周折去找他——因为他会主动送上门来。\r\n  \r\n  2、如果他答应你的事却没有做到,哪怕那只是一个电话。\r\n  \r\n  “他真的很忙所以忘了”“至少他真的与我道歉了”……他很忙,\r\n  \r\n  即将就任美国总统,一个小时好几亿的生意要谈,忙得快疯了,\r\n  \r\n  一天根本抽不出时间与你打电话,忙得真疯呀。\r\n  \r\n  有手机、有快速拨号、甚至有语音拨号,\r\n  \r\n  有时压根没想打电话,电话就从裤兜里拨出去了,\r\n  \r\n  为什么没有时间打电话。\r\n  \r\n  如果真的喜欢你就不会忘记,如果忘记说明他不在乎你失望。\r\n  \r\n  “忙”就是恋爱上的大规模杀伤性武器,是“混蛋”的同义词,\r\n  \r\n  混蛋就是用忙敷衍你的那个人。\r\n  \r\n  ——(心智健全的)男人知道什么叫“轻重缓急”,至于道歉?\r\n  \r\n  噢,没有时间听他胡说八道。\r\n  \r\n  3、如果他暧昧不清。\r\n  \r\n  “他以前受过伤”“他现在生活很混乱”\r\n  \r\n  “他刚刚分手/离婚,他想慢慢来”“他习惯了自由”……\r\n  \r\n  这些全是都市神话,用来对付男人不喜欢的女孩,\r\n  \r\n  如果他喜欢你,就不会暧昧不清,就会昭告天下对你的所有权,\r\n  \r\n  他不愿意见你的朋友和家人,\r\n  \r\n  说因为是和你在一起而不是要和***谈恋爱,\r\n  \r\n  他不愿意带你走进他的圈子,说因为这只是两个人的事,\r\n  \r\n  如果他用以上种种借口解释你们之间的暧昧,\r\n  \r\n  那么请自动翻译成“我只想用你来消磨时间”“我不太喜欢你”。\r\n  \r\n  4、如果他不愿意与你太亲近。\r\n  \r\n  Gerg说得无比直接,\r\n  \r\n  “我是男人,如果我喜欢你,我就吻你,会想看你穿内衣和不穿内衣的样子。”,\r\n  \r\n  虽然觉得很囧很寒,但是想想也是实话吧,\r\n  \r\n  如果喜欢你就应该是喜欢你的内在和外在,\r\n  \r\n  难道你要一个喜欢你的人与你说“我很爱你,让我成为你的心灵之友吧”……\r\n  \r\n  我估计柏拉图他老人家也不会这么说。\r\n  \r\n  5、如果他背叛你。\r\n  \r\n  “他喝多了”“那只是偶尔出现的意外”“他是不小心的”……\r\n  \r\n  Gerg说得很对,背叛没有借口。\r\n  \r\n  背叛这种事情是不会“不小心就发生”的,\r\n  \r\n  他不可能说“噢,我不小心摔了一跤,正好摔到别人床上去了。”\r\n  \r\n  明知会破坏恋爱中的规矩还要去实施,\r\n  \r\n  你应该直接把他甩掉,最糟糕的是有人可能因此怀疑自己的魅力,\r\n  \r\n  是不是应该整容是不是应该减肥,\r\n  \r\n  Gerg说得很酷:“你需要减掉的不是20磅,\r\n  \r\n  而是175磅——你那没出息的男朋友的体重。”\r\n  \r\n  6、如果他都喝得醉醺醺才来找你。\r\n  \r\n  他酗酒、或者吸毒(这个在国内应该不普遍),\r\n  \r\n  而不愿意为你改变,那么就该离开,因为长远的生活是需要清醒的。\r\n  \r\n  7、如果时机成熟但他依然不想结婚。\r\n  \r\n  “也许是我思想太不开放”“他受到童年家庭阴影”“他还没准备好”……\r\n  \r\n  许多男人、女人、心理学家、社会学家、人类学家、女权主义者...\r\n  \r\n  都可以滔滔不绝的进行一场批判婚姻制度的讲座,\r\n  \r\n  告诉你婚姻是落后的制度是古老的财务契约,\r\n  \r\n  可是很抱歉,首先你要搞清楚“不想结婚”可能仅仅意味着“不想和你结婚”,\r\n  \r\n  那些说“不想结婚”人最后一定会结婚,只是不是和你。\r\n  \r\n  8、如果他不断的与你分手,然后又来找你和好。\r\n  \r\n  首先请保持风度,不要再打电话传简讯给他,如果分手,那就是分手。\r\n  \r\n  你不要觉得只要他回来找你,你就可以继续跟他聊天、见面、看电影,\r\n  \r\n  为他做饭、买礼物、刻CD、喂鱼,问候他的父母和朋友,\r\n  \r\n  偷用他的语音信箱查询他的通话记录。。。。。\r\n  \r\n  真正喜欢你的人不会要和你分手,不会翻来覆去的折腾你,\r\n  \r\n  所以麻烦你清醒点,除非你想成为悠悠球冠军小姐。\r\n  \r\n  9、如果他突然莫名其妙的消失了。\r\n  \r\n  不要花费巨大的精力来解决“失踪男人之谜”,\r\n  \r\n  无论你找出了各种各样可以安慰自己的证据和借口,\r\n  \r\n  唯一的事实是,他不再想和你在一起,\r\n  \r\n  并且没有胆量和你说清楚。\r\n  \r\n  请相信,没有什么秘密——他配不上你。\r\n  \r\n  10、如果他是已婚。\r\n  \r\n  没什么好说的,至少在他离婚之前。\r\n  \r\n  如果你还想不通,那么大概应该报警——有人把大脑丢了。\r\n  \r\n  有时我们宁愿相信一个男人太害怕、太紧张、太自卑、太圣洁、\r\n  \r\n  太爱前女友、太敏感、太恋母、太忙、童年阴影太多、\r\n  \r\n  家庭压力太大、太累、太疯、晒得太黑、太有自杀倾向……\r\n  \r\n  却不愿意看清很简单的事实,\r\n  \r\n  是的,他不是太忙,不是受过伤,\r\n  \r\n  不是有童年阴影,不是遇到了地震洪水,\r\n  \r\n  不是要就任美国总统,不是脑震荡得了短暂性失忆,\r\n  \r\n  不是手机掉进了火锅,他不是有健忘症,\r\n  \r\n  他也不是死了——他只是没有那么喜欢你而已。\r\n  \r\n  "})

总结

1、通过使用nodejs实现抓数据,发现就是不一样,就像原始的用javascript操作DOM一样方便,这得益于模块cheerio,它是nodejs特别为服务器定制,快速灵活实施的Jquery核心实现。cheerio工作于DOM模型上,且解析、操作、呈送都很高效,据基准测试:cheerio大约比JsDom快8倍。

cheerio的使用:

1 //方式一
2 var cheerio = require("cheerio");
3 var $ = cheerio.load(doc);
4 $("p").attr("id","test");
5
6 //方式二
7 var $= require("cheerio");
8 $("p").attr("id","test");

2、另外一个就是iconv-lite,它的作用就是解决编码问题,可以认为是一种标准字符集转换接口,用于在不同字符集编码之间进行转换,注意:nodejs自带的toString()方法是不能解决中文编码问题的。
官方资料:iconv-lite支持的编码包括node.js原生编码:utf8, ucs2, ascii, binary, base64;同时支持广泛使用的单字节编码:Windows 125x family, ISO-8859 family, IBM/DOS codepages, Macintosh family, KOI8 family, latin1, us-ascii;多字节编码:gbk, gb2313, Big5, cp950。

iconv-lite的使用:

1 var iconv = require(‘iconv-lite‘);
2 //将nodejs的原生编码转换成其他编码
3 var val = iconv.decode(bufferHelper.toBuffer(), ‘gb2312‘);

3、在做字符处理,特别是GB2312,GBK格式,例如GBK格式英文占用1个字节,汉字占2个字节,当执行ondata时,匿名函数的参数chunk其实是一个Buffer对象,如下代码:

1 res.on(‘data‘, function (chunk) {
2             bufferHelper.concat(chunk);
3 });

当你换成用result+=chunk时,其实隐式的将chunk做了toStrinig()处理,于是到了最后,不管你用下面哪种方式都会报错
1.var iconv = new Iconv(‘GBK‘, ‘UTF-8‘); iconv.convert(result).toString(); 

2.iconv.decode(result , ‘gb2312‘);

原因:你对Buffer对象做了加法操作,字符截断,导致解码出错。

bufferhelper的使用:

1 var BufferHelper = require(‘bufferhelper‘);
2 var bufferHelper = new BufferHelper();
3 bufferHelper.concat(chunk);

结束,睡觉

------如果你觉得此文对你有所帮助,别忘了点击下右下角的推荐咯,谢谢!------

时间: 2024-07-28 15:04:52

使用NodeJs,实现数据抓取的相关文章

Phantomjs+Nodejs+Mysql数据抓取(2.抓取图片)

概要 这篇博客是在上一篇博客Phantomjs+Nodejs+Mysql数据抓取(1.抓取数据) http://blog.csdn.net/jokerkon/article/details/50868880 后进行的第二部分,请各位读者在看这篇博客之前先浏览上一篇,因为这里面有部分代码会沿用到上一部分的抓取结果. 好,现在开始正式的抓取图片的讲解 首先,我们先来看看代码: var page =require('webpage').create(); var address='http://pro

Phantomjs+Nodejs+Mysql数据抓取(1.数据抓取)

概要: 这篇博文主要讲一下如何使用Phantomjs进行数据抓取,这里面抓的网站是太平洋电脑网估价的内容.主要是对电脑笔记本以及他们的属性进行抓取,然后在使用nodejs进行下载图片和插入数据库操作. 先进行所有页面的内容进行抓取 var page =require('webpage').create(); var address='http://product.pconline.com.cn/server/'; var fs = require('fs'); var mypath = 'ver

nodejs爬虫数据抓取乱码问题总结

一.非UTF-8页面处理 1.背景 windows-1251编码 比如俄语网站:https://vk.com/cciinniikk 可耻地发现是这种编码 所有这里主要说的是 Windows-1251(cp1251)编码与utf-8编码的问题,其他的如 gbk就先不考虑在内了~ 2.解决方案 1. 使用js原生编码转换 但是我现在还没找到办法哈.. 如果是utf-8转window-1251还可以 http://stackoverflow.com/questions/2696481/encoding

nodejs爬虫数据抓取 -- 问题总结

一  返回的信息提示  Something went wrong  request模块请求出现未知错误 其中,所用代码如下(无User-Agent部分) 问题多次派查无果,包括: 1:postman请求正常 2. curl 请求正常 解决办法: 为请求添加user-agent头,如取消上注释部分.(我发现,只要有了user-agent这个key,无论其value是否为空,都可以正常返回了) 所以对于模拟请求,有时候相应的http头部信息还是必须的.

ngrep环回接口数据抓取方法,使用-d lo参数

ngrep环回接口数据抓取方法,使用-d lo参数,注意顺序: ngrep -W byline -d lo port 80

利用Selenium制作python数据抓取,以及对Selenium资源介绍

当当当~第三篇博客开始啦~ 这次的话题是数据抓取.终于到了核心部分的探讨,我的心情也是非常激动啊!如果大家baidu或者google(如果可以的话)数据抓取或者data crawling,将会找到数以千计的例子.但是大多数的代码非常的冗长,并且许多代码还是抓取静态数据之后,对动态JS写成的数据却毫无办法.或者,利用HTML解析网址后,再找到JS写的数据页面来寻找到所想要的数据. 但是!不知各位是否有发现过,如果打开chrome或者safari或者各种浏览器的审查元素.网页上能看到的数据,其实都会

delphi 用idhttp做web页面数据抓取 注意事项

这里不讨论webbrowse方式了 .直接采用indy的 idhttp  Get post 可以很方便的获取网页数据. 但如果要抓取大量数据 程序稳定运行不崩溃就不那么容易了.这几年也做了不少类似工具 总结了几点 好记性不如烂笔头. 内存泄露 获取页面文本 少不了用到html解析 具体到delphi 估计采用mshtml htmltotext 方法的不少,这个方案再大数据量时就会内存溢出 导致程序崩溃,而这并不是每个程序员都知道.解决的方案:采用自己的html解析类 这里我要感谢 武稀松(csd

数据抓取的艺术(一):Selenium+Phantomjs数据抓取环境配置

数据抓取的艺术(一):Selenium+Phantomjs数据抓取环境配置 2013-05-15 15:08:14 分类: Python/Ruby 数据抓取是一门艺术,和其他软件不同,世界上不存在完美的.一致的.通用的抓取工具.为了不同的目的,需要定制不同的代码.不过,我们不必Start from Scratch,已经有许多的基本工具.基本方法和基础框架可供使用.不同的工具.不同的方法.不同的框架的特点也不同.了解这些工具.方法和框架是首要任务,接下来就需要明白它们的差异都在哪里.什么情境该用什

C# 微信 生活助手 空气质量 天气预报等 效果展示 数据抓取 (一)

第一次在博客园写博客写的不好,大家见谅.最近工作辞了,然后感冒发烧输了一个星期的液,感觉很烦躁,心情不是很好,在帝都感觉压力大,废话不说了开始正题把! 还没有完全完成,后续考虑开源! 可以关注微信公众帐号体验一下先看下 效果把 先介绍下工具 我用的有 httpwatch,fiddler 国家环保部的数据链接 http://datacenter.mep.gov.cn/report/air_daily/airDairyCityHour.jsp 原以为直接get请求就可以了 试了下 发现没有获取了 然

数据抓取的艺术(三):抓取Google数据之心得

本来是想把这部分内容放到前一篇<数据抓取的艺术(二):数据抓取程序优化>之中.但是随着任务的完成,我越来越感觉到其中深深的趣味,现总结如下: (1)时间     时间是一个与抓取规模相形而生的因素,数据规模越大,时间消耗往往越长.所以程序优化变得相当重要,要知道抓取时间越长,出错的可能性就越大,这还不说程序需要人工干预的情境.一旦运行中需要人工干预,时间越长,干预次数越多,出错的几率就更大了.在数据太多,工期太短的情况下,使用多线程抓取,也是一个好办法,但这会增加程序复杂度,对最终数据准确性产