学习笔记

前言

近期做一个数据抓爬工具,最开始使用的是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代码于运行结果

 var http = require('http');
var _url = require('url'); //引用url模块,处理url地址相关操作
var cheerio = require("cheerio"); //引用cheerio模块,使在服务器端像在客户端上操作DOM,不用正则表达式
var iconv = require('iconv-lite'); //解决编码转换模块
var BufferHelper = require('bufferhelper'); //关于Buffer我后面细说
/*
*最后我需要达到的效果是,给予一个访问地址,形如:http://www.mynode.com?link=www.abc.com&callback=cb
*我希望可以返回json,也可返回jsonp
*/ http.createServer(function (req, res) {
var arg = _url.parse(req.url, true).query; //通过调用url模块,获取查询字符串参数集合
var link = arg.link; //获取抓取的link
var callback = arg.callback; //回调函数的名称
//若没有对link加上http,则补全
var protocol = "http";
if (link.indexOf("http") < 0) {
link = protocol + "://" + link;
}
//抓取页面
download(link, function (data) {
res.writeHead(200, {
"Content-Type": "text/html;charset=utf-8",
"Transfer-Encoding": "chunked"
});
var doc = data.toString();
var $ = cheerio.load(doc);
var list = [];
$(".e2 li .title").each(function (i, e) {
var item = $(e).children("a").last();
var title = item.text();
var link = item.attr("href");
list.push({ "title": title, "link": link });
});
var jsonText = JSON.stringify(list);
if (callback) {
res.write(callback + "(" + jsonText + ")");
}
else {
res.write(jsonText);
}
res.end();
});
}).listen(process.env.PORT); //加载第三方页面
function download(url, callback) {
http.get(url, function (res) {
var bufferHelper = new BufferHelper(); //解决中文编码问题
res.on('data', function (chunk) {
bufferHelper.concat(chunk);
});
res.on("end", function () {
//注意,此编码必须与抓取页面的编码一致,否则会出现乱码,也可以动态去识别
var val = iconv.decode(bufferHelper.toBuffer(), 'gb2312');
callback(val);
});
}).on("error", function () {
callback(null);
});
}

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的使用:

 //方式一
var cheerio = require("cheerio");
var $ = cheerio.load(doc);
$("p").attr("id","test"); //方式二
var $= require("cheerio");
$("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的使用:

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

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

 res.on('data', function (chunk) {
bufferHelper.concat(chunk);
});

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

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

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

bufferhelper的使用:

 var BufferHelper = require('bufferhelper');
var bufferHelper = new BufferHelper();
bufferHelper.concat(chunk);

结束,睡觉

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

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

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

    概要 这篇博客是在上一篇博客Phantomjs+Nodejs+Mysql数据抓取(1.抓取数据) http://blog.csdn.net/jokerkon/article/details/50868 ...

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

    概要: 这篇博文主要讲一下如何使用Phantomjs进行数据抓取,这里面抓的网站是太平洋电脑网估价的内容.主要是对电脑笔记本以及他们的属性进行抓取,然后在使用nodejs进行下载图片和插入数据库操作. ...

  3. [nodejs,expressjs,angularjs2] LOL英雄列表数据抓取及查询显示应用

    新手练习,尝试使用angularjs2 [angularjs2 数据绑定,监听数据变化自动修改相应dom值,非常方便好用,但与传统js(jquery)的使用方法会很不同,Dom操作也不太习惯] 应用效 ...

  4. [原创.数据可视化系列之十二]使用 nodejs通过async await建立同步数据抓取

    做数据分析和可视化工作,最重要的一点就是数据抓取工作,之前使用Java和python都做过简单的数据抓取,感觉用的很不顺手. 后来用nodejs发现非常不错,通过js就可以进行数据抓取工作,类似jqu ...

  5. Java实现多种方式的http数据抓取

    前言: 时下互联网第一波的浪潮已消逝,随着而来的基于万千数据的物联网时代,因而数据成为企业的重要战略资源之一.基于数据抓取技术,本文介绍了java相关抓取工具,并附上demo源码供感兴趣的朋友测试! ...

  6. R语言XML包的数据抓取

    htmlParse 函数 htmlParse加抓HTML页面的函数. url1<-"http://www.caixin.com/"url<-htmlParse(url1 ...

  7. Twitter数据抓取

    说明:这里分三个系列介绍Twitter数据的非API抓取方法.有兴趣的QQ群交流: BitCrawler网络爬虫QQ群 322937592 1.Twitter数据抓取(一) 2.Twitter数据抓取 ...

  8. python3爬虫再探之豆瓣影评数据抓取

    一个关于豆瓣影评的爬虫,涉及:模拟登陆,翻页抓取.直接上代码: import re import time import requests import xlsxwriter from bs4 imp ...

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

     数据抓取的艺术(一):Selenium+Phantomjs数据抓取环境配置 2013-05-15 15:08:14 分类: Python/Ruby     数据抓取是一门艺术,和其他软件不同,世界上 ...

  10. python爬虫数据抓取方法汇总

    概要:利用python进行web数据抓取方法和实现. 1.python进行网页数据抓取有两种方式:一种是直接依据url链接来拼接使用get方法得到内容,一种是构建post请求改变对应参数来获得web返 ...

随机推荐

  1. AMQ学习笔记 - 11. Spring-JmsTemplate之执行

    概述 前面我们分别介绍了发送.接收和浏览,这三个的实现都依赖于将要介绍的执行. 执行算是一个相对比较底层的方法系列,一般情况下,我们不需要直接面向将要介绍的方法. 执行 1.关于回调接口 在讲执行之前 ...

  2. 在hibernate中使用c3p0数据源

    1.  jar包  hibernate-release-4.1.8.Final\lib\optional\c3p0 2.  加入配置:   <!-- 数据库连接池最大连接数 -->  &l ...

  3. 使用notepad++编辑器

    使用notepad++编辑器 在公司时经常要用到文本编辑器去写jsp文件,之前使用的是sublime text 3,但是觉得不太顺手,于是转用notepad++编辑器. 这个编辑器最吸引我的地方是层次 ...

  4. java检测端口号是否配占用

    java检测端口号是否被占用的工具类:       package com.frank.util; import java.io.IOException; import java.net.InetAd ...

  5. IEEE 802.15.4协议学习之物理层

    在详细讲述IEEE 802.15.4协议之前,谈谈自己这两个星期看协议过程中的一点心得,或者是收获吧. 看协议文档,一定要看有书签的,边看边在旁边做些备注,以便于后期整理.对于协议层次相关的,最好在纸 ...

  6. ISE 中使用system generate

    本文讲解简单的ISE中使用system generate,system generate基本使用规则在此不详细说明可以见博客http://blog.csdn.net/xiabodan/article/ ...

  7. 已成功与服务器建立连接,但是在登录前的握手期间发生错误。 (provider: SSL Provider, error: 0 - 等待的操作过时)

    今天忽然间发现远程连接别人数据库会出现  已成功与服务器建立连接,但是在登录前的握手期间发生错误. (provider: SSL Provider, error: 0 - 等待的操作过时)  这种情况 ...

  8. 运行yum报错Error: Cannot retrieve metalink for repository: epel. Please verify its path and try again

    今天给Centos通过rpm -Uvh装了个epel的扩展后,执行yum就开始报错: Error: Cannot retrieve metalink for repository: epel. Ple ...

  9. Amazon S3 PHP Class Documentation

    API : http://undesigned.org.za/2007/10/22/amazon-s3-php-class/documentation Example: http://www.phpb ...

  10. Sending Email from mailx Command in Linux Using Gmail’s SMTP

    The mailx or mail command in Linux is still providing service for guys like me, especially when we n ...