Nodejs,不一样的爬虫实践
来自: http://www.famanoder.com/bokes/56b0ff763b9d992825f0a1bb
做前端以来,对我成长帮助最大的恐怕也就是各位大侠们的博客了, ,慢慢的也在我心里种下了颗种子:我也要写博客!哪怕我文笔差,技术菜,难以望其项背,我也要追随大神们的脚步,写写博客,处处留香。摸爬滚打,终是成长;学习分享,与君共勉!小前端初学Nodejs,搭了个 简单的博客 ,捉襟见肘,望大侠路过指导!好了,此处有广告之嫌,进入正题。
关于Nodejs的爬虫程序,百度一大把,是的,我也是百度到的,然后到github上看了看cheerio模块;乍一看,这不就是Jquery嘛,没想到Jquery都能牛到后端操作DOM了啊,恩。。。可以先这么认为和理解吧,因为cheerio确实可以像jquery操作DOM一样操作从远程爬取过来的页面;顿时邪念四起:我要把我喜欢的博客全抓到我的博客站点上去、我要不KX上网而是把谷歌抓过来访问。。。然后就有了我博客上的 “爬呀爬” 版块,都是爬取的国内顶尖的前端团队呕心沥血写的博客, ,保留了作者信息和版权,当然,如果他们看到了,骂我一顿,叫我删掉,我肯定会屁颠屁颠删掉的;
还有就是怎么通过我的站点访问谷歌了,比如:http://www.famanoder.com?url=http://google.com的请求,我res.send(googleBody);恩 ,这样是可以的,可是问题在于:相对路径的资源返回404了,因为相对路径域名取的是我的站点,而我的站点没有对应的目录和资源,自然404了;这时cheerio可就很有用了,在res.send之前可以对body进行些DOM操作啊,貌似有点复杂啊,我正则还不行。。。为了让爬取过来的谷歌可以点击,链接没有404,还需要做一步,就是通过cheerio将所有相对路径补上http://www.famanoder.com?url=http://google.com,绝对路径补上http://www.famanoder.com?url=来将爬取的目标站点所有资源都通过我的博客站点请求;
很高兴,一个小小的爬虫让我我又知道了三个很好用的模块:request、superagent、cheerio ;
request和superagent差不多,过年后做个横向的比较,争取进一步理解http模块;
先看看request怎么抓页面的吧,江湖中人不多废话了,看代码:
if (req.query.url) { var iurl = decodeURIComponent(req.query.url); var thaturl = url.parse(iurl).protocol +url.parse(iurl).host; var body=[],size=0; request.get({ url: iurl, headers: { } }) .on('response', function (response) { res.set(response.headers); response.setEncoding='utf8'; response.on('data',function(chunk){ body.push(chunk); size+=chunk.length; }); }) .on('error', function (err) { console.log(err); }) .on('end',function(){ //buffer 防止丢包的情况,如果数据过多,会抓不全的。。。。。 var data = Buffer.concat(body , size); var html = data.toString(); var $=cheerio.load(html); //只是个栗子,具体情况还会要url.parse解析所有href、src再处理 $('a').each(function(){ $(this).attr('href','http://famanoder.com?url='+$(this).attr('href')); }); res.write($('html,body').html()); }) //.pipe(res); }
除了丢包,一般不会有什么问题了,可能就是unicode中文的乱码了,也有很多模块可以处理,不过用JS弄也不错,谢谢某大侠的代码,找半天了,值得收藏:
function reconvert(str){ str = str.replace(/(\\u)(\w{4})/gi,function($0){ return (String.fromCharCode(parseInt((escape($0).replace(/(%5Cu)(\w{4})/g,"$2")),16))); }); str = str.replace(/(&#x)(\w{4});/gi,function($0){ return String.fromCharCode(parseInt(escape($0).replace(/(%26%23x)(\w{4})(%3B)/g,"$2"),16)); }); return str; }
对了,抓取来的body是不能直接操作的,不信试一试,不用cheerio而是直接toString再replace什么的,都是无用功;
好吧,到这我一口气爬取了上百篇大神们的博客, ,还是有些繁琐的,巴拉巴拉,我想还是弄个定时任务吧,每天到点就爬一页,取最新的留下;这里也有两个模块供选择:schedule、later,还是下次做个横向的比较吧,期待。schedule这个单词在学校时就没写对过,今天终于写对了,原谅我,又掉底子了。。。看看定时任务吧:
var registTask=function(hour,minute,taskname,fn){ var rule = new schedule.RecurrenceRule(); //每天这个时刻定时执行任务 rule.dayOfWeek = [0, new schedule.Range(1, 6)]; rule.hour = hour; rule.minute = minute; var j = schedule.scheduleJob(rule, function(){ console.log("开始爬取:"+taskname); fn&&fn(); }); } registTask(23,30,'TaoBaoFED',function(){ getTaoBaoFEDBokes(1); //呵呵,每天23:30爬一页 });
差不多这就是“爬呀爬” 这个小玩意,对于一个业余的noder来说,又走了一小步,也挺好玩的;马上就过年了,又要老一岁了啊,不过也很快就到春天了,祝大家猴年大吉,四季如春!