【原】小玩node+express爬虫-2
上周写了一个node+experss的爬虫小入门。今天继续来学习一下,写一个爬虫2.0版本。
这次我们不再爬博客园了,咋玩点新的,爬爬电影天堂。因为每个周末都会在电影天堂下载一部电影来看看。
talk is cheap,show me the code!
【原】小玩node+express爬虫-1:http://www.cnblogs.com/xianyulaodi/p/6049237.html
抓取页面分析
我们的目标:
1、抓取电影天堂首页,获取左侧最新电影的169条链接
2、抓取169部新电影的迅雷下载链接,并且并发异步抓取。
具体分析如下:
1、我们不需要抓取迅雷的所有东西,只需要下载最新发布的电影即可,比如下面的左侧栏。一共有170个,除去第一个(因为第一个里面有200部电影),一共有169部电影。
2、除了抓取首页的东西,我们还要抓取点进去之后,每部电影的迅雷下载链接
环境搭建
1、需要的东西:node环境、express、cherrio 这三个都是上一篇文章有介绍的,所以这里不再做介绍:点击查看
2、需要安装的新东西:
superagent:
作用:跟request差不多,我们可以用它来获取get/post等请求,并且可以设置相关的请求头信息,相比较使用内置的模块,要简单很多。
用法:
var superagent = require('superagent');
superagent
.get('/some-url')
.end(function(err, res){
// Do something
});
superagent-charset:
作用:解决编码问题,因为电影天堂的编码是gb2312,爬取下来的中文会乱码掉。
用法:
var superagent = require('superagent');
var charset = require('superagent-charset');
charset(superagent); superagent
.get('/some-url')
.charset('gb2312') //这里设置编码
.end(function(err, res){
// Do something
});
async:
作用:Async是一个流程控制工具包,提供了直接而强大的异步功能,在这里作为处理并发来调用。
用法:这里需要用到的是:async.mapLimit(arr, limit, iterator, callback)
mapLimit可以同时发起多个异步操作,然后一起等待callback的返回,返回一个就再发起下一个。
arr是一个数组,limit并发数,将arr中的每一项依次拿给iterator去执行,执行结果传给最后的callback
eventproxy:
作用:eventproxy 起到了计数器的作用,它来帮你管理到底异步操作是否完成,完成之后,它会自动调用你提供的处理函数,并将抓取到的数据当参数传过来。
例如我首先抓取到电影天堂首页侧栏的链接,才可以接着抓取链接里面的内容。具体作用可以点这里
用法:
var ep = new EventProxy();
ep.after('got_file', files.length, function (list) {
// 在所有文件的异步执行结束后将被执行
// 所有文件的内容都存在list数组中
});
for (var i = 0; i < files.length; i++) {
fs.readFile(files[i], 'utf-8', function (err, content) {
// 触发结果事件
ep.emit('got_file', content);
});
}
//注意got_file这两个名字必须对应
开始爬虫
主要的程序在app.js这里,所以看的话可以主要看app.js即可
1、首先定义一些全局变量,该引入的库引进来
var cheerio = require('cheerio'); //可以像jquer一样操作界面
var charset = require('superagent-charset'); //解决乱码问题:
var superagent = require('superagent'); //发起请求
charset(superagent);
var async = require('async'); //异步抓取
var express = require('express');
var eventproxy = require('eventproxy'); //流程控制
var ep = eventproxy();
var app = express(); var baseUrl = 'http://www.dytt8.net'; //迅雷首页链接
var newMovieLinkArr=[]; //存放新电影的url
var errLength=[]; //统计出错的链接数
var highScoreMovieArr=[] //高评分电影
2、开始爬取首页迅雷首页:
//先抓取迅雷首页
(function (page) {
superagent
.get(page)
.charset('gb2312')
.end(function (err, sres) {
// 常规的错误处理
if (err) {
console.log('抓取'+page+'这条信息的时候出错了')
return next(err);
}
var $ = cheerio.load(sres.text);
// 170条电影链接,注意去重
getAllMovieLink($);
highScoreMovie($);
/*
*流程控制语句
*当首页左侧的链接爬取完毕之后,我们就开始爬取里面的详情页
*/
ep.emit('get_topic_html', 'get '+page+' successful');
});
})(baseUrl);
在这里,我们先抓取首页的东西,把首页抓取到的页面内容传给 getAllMovieLink和highScoreMovie这两个函数来处理,
getAllMovieLink获取到了左侧栏除了第1部的电影的169电影。
highScoreMovie为左侧栏第一个链接,里面的都是评分比较高的电影。
上面的代码中,我们弄了一个计数器,当它执行完之后,我们就可以执行与‘get_topic_html‘名字对应的流程了,从而可以保证在执行完首页的抓取工作之后,再执行次级页面的抓取工作。
ep.emit('get_topic_html', 'get '+page+' successful');
highScoreMovie方法如下,其实我们这里的作用不大,只是我统计一下高评分电影首页的信息,懒的继续抓取了
//评分8分以上影片 200余部!,这里只是统计数据,不再进行抓取
function highScoreMovie($){
var url='http://www.dytt8.net'+$('.co_content2 ul a').eq(0).attr('href');
console.log(url);
superagent
.get(url)
.charset('gb2312')
.end(function (err, sres) {
// 常规的错误处理
if (err) {
console.log('抓取'+url+'这条信息的时候出错了')
}
var $ = cheerio.load(sres.text);
var elemP=$('#Zoom p');
var elemA=$('#Zoom a');
for (var k = 1; k < elemP.length; k++) {
var Hurl=elemP.eq(k).find('a').text();
if(highScoreMovieArr.indexOf(Hurl) ==-1){
highScoreMovieArr.push(Hurl);
};
}
});
}
3、分离出左侧栏的信息,
如下图,首页中,详情页的链接都在这里$('.co_content2 ul a')。
因此我们将左侧栏这里的详情页链接都遍历出来,保存在一个newMovieLinkArr这个数组里面。
getAllMovieLink方法如下:
// 获取首页中左侧栏的所有链接
function getAllMovieLink($){
var linkElem=$('.co_content2 ul a');
for(var i=1;i<170;i++){
var url='http://www.dytt8.net'+linkElem.eq(i).attr('href');
// 注意去重
if(newMovieLinkArr.indexOf(url) ==-1){
newMovieLinkArr.push(url);
};
}
}
4、对获取到的电影详情页进行爬虫,提取有用信息,比如电影的下载链接,这个是我们所关心的。
// 命令 ep 重复监听 emit事件(get_topic_html),当get_topic_html爬取完毕之后执行
ep.after('get_topic_html', 1, function (eps) {
var concurrencyCount = 0;
var num=-4; //因为是5个并发,所以需要减4 // 利用callback函数将结果返回去,然后在结果中取出整个结果数组。
var fetchUrl = function (myurl, callback) {
var fetchStart = new Date().getTime();
concurrencyCount++;
num+=1
console.log('现在的并发数是', concurrencyCount, ',正在抓取的是', myurl);
superagent
.get(myurl)
.charset('gb2312') //解决编码问题
.end(function (err, ssres) { if (err) {
callback(err, myurl + ' error happened!');
errLength.push(myurl);
return next(err);
} var time = new Date().getTime() - fetchStart;
console.log('抓取 ' + myurl + ' 成功', ',耗时' + time + '毫秒');
concurrencyCount--; var $ = cheerio.load(ssres.text); // 对获取的结果进行处理函数
getDownloadLink($,function(obj){
res.write('<br/>');
res.write(num+'、电影名称--> '+obj.movieName);
res.write('<br/>');
res.write('迅雷下载链接--> '+obj.downLink);
res.write('<br/>');
res.write('详情链接--> <a href='+myurl+' target="_blank">'+myurl+'<a/>');
res.write('<br/>');
res.write('<br/>');
});
var result = {
movieLink: myurl
};
callback(null, result);
});
}; // 控制最大并发数为5,在结果中取出callback返回来的整个结果数组。
// mapLimit(arr, limit, iterator, [callback])
async.mapLimit(newMovieLinkArr, 5, function (myurl, callback) {
fetchUrl(myurl, callback);
}, function (err, result) {
// 爬虫结束后的回调,可以做一些统计结果
console.log('抓包结束,一共抓取了-->'+newMovieLinkArr.length+'条数据');
console.log('出错-->'+errLength.length+'条数据');
console.log('高评分电影:==》'+highScoreMovieArr.length);
return false;
}); });
首先是async.mapLimit对所有详情页做了一个并发,并发数为5,然后再爬取详情页,爬详情页的过程其实和爬首页的过程是一样的,所以这里不做过多的介绍,然后将有用的信息打印到页面上。
5、执行命令之后的图如下所示:
浏览器界面:
这样,我们爬虫的稍微升级版就就完成啦。可能文章写的不是很清楚,我已经把代码上传到了github上,可以将代码运行一遍,这样的话比较容易理解。后面如果有时间,可能会再搞一个爬虫的升级版本,比如将爬到的信息存入mongodb,然后再在另一个页面展示。而爬虫的程序加个定时器,定时去抓取。
备注:如果运行在浏览器中的中文乱码的话,可以将谷歌的编码设置为utf-8来解决;
代码地址:https://github.com/xianyulaodi/mySpider2
有误之处,欢迎指出
【原】小玩node+express爬虫-2的更多相关文章
- 【原】小玩node+express爬虫-1
最近开始重新学习node.js,之前学的都忘了.所以准备重新学一下,那么,先从一个简单的爬虫开始吧. 什么是爬虫 百度百科的解释: 爬虫即网络爬虫,是一种自动获取网页内容的程序.是搜索引擎的重要组成部 ...
- node:爬虫爬取网页图片
代码地址如下:http://www.demodashi.com/demo/13845.html 前言 周末自己在家闲着没事,刷着微信,玩着手机,发现自己的微信头像该换了,就去网上找了一下头像,看着图片 ...
- node express
在某QQ群里,发现大家都在搞node,为了不被out,这周主要研究了一下,还挺高大上. 参考了下资料,适合初学者学习. Node和NPM的安装够便捷了,不细说...有几点基础顺手提一下: 安装命令中的 ...
- Webpact打包React后端Node+Express
Webpact打包React后端Node+Express 前言 React官方推荐用Browserify或者Webpack 来开发React组件. Webpack 是什么?是德国开发者 Tobias ...
- 零基础实现node+express个性化聊天室
本篇文章使用node+express+jquery写一个个性化聊天室,一起来get一下~(源码地址见文章末尾) 效果图 项目结构 实现功能 登录检测 系统自动提示用户状态(进入/离开) 显示在线用户 ...
- node+express+mongodb初体验
从去年11月份到现在,一直想去学习nodejs,在这段时间体验了gulp.grunt.yeomen,fis,但是对于nodejs深入的去学习,去开发项目总是断断续续. 今天花了一天的时间,去了解整理整 ...
- 运用 node + express + http-proxy-middleware 实现前端代理跨域的 详细实例哦
一.你需要准备的知识储备 运用node的包管理工具npm 安装插件.中间件的基本知识: 2.express框架的一些基础知识,知道如何建立一个小的服务器:晓得如何快速的搭建一个express框架小应用 ...
- react + node + express + ant + mongodb 的简洁兼时尚的博客网站
前言 此项目是用于构建博客网站的,由三部分组成,包含前台展示.管理后台和后端. 此项目是基于 react + node + express + ant + mongodb 的,项目已经开源,项目地址在 ...
- Kubernetes实战 - 从零开始搭建微服务 - 1.5 提高可用性-发布多节点的Node/Express网络应用程序
1.5 提高可用性-发布多节点的Node/Express网络应用程序 Kubernetes实战 - 从零开始搭建微服务 前言 在上一篇文章中,已经学习了如何简单地开发一个单层网络应用.[Kuberne ...
随机推荐
- Microsoft Dynamics CRM 2013 Js Odata 查询
实现功能: 在新建记录时,(大区,省区,城市)的值默认为当前用户的值.tips:字段均为lookup类型; function Default_region(){ var fromtype=Xrm. ...
- 最快让你上手ReactiveCocoa之基础篇
前言 很多blog都说ReactiveCocoa好用,然后各种秀自己如何灵活运用ReactiveCocoa,但是感觉真正缺少的是一篇如何学习ReactiveCocoa的文章,这里介绍一下. 1.Rea ...
- Spring下如何配置bean
本次讲述项目背景: 创建Service类,Service下用到dao类.通过在Spring中配置bean,实现在项目启动时,自动加载这个类 本次只讲述配置bean的注意事项,故只给出简单实例: 创建S ...
- MySql索引总结
索引概念 B+树索引分为聚集索引和非聚集索引(辅助索引),但是两者的数据结构都和B+树一样,区别是存放的内容. 可以说数据库必须有索引,没有索引则检索过程变成了顺序查找,O(n)的时间复杂度几乎是不能 ...
- tcpdump、nc网络工具使用
tcpdump: 网络嗅探器 nc: nmap: 端口扫描 混杂模式(promisc) C设置为监控,当A和B通信,C是无法探测到数据的,除非有交换机的权限,将全网端口的数据通信都发送副本到C的端口上 ...
- 个人CTF资源聚合
i春秋 幻泉 CTF入门课程笔记 视频地址 能力 思维能力 快速学习能力 技术能力 基础 编程基础 (c语言 汇编语言 脚本语言) 数学基础 (算法 密码学) 脑洞 (天马行空的想象推理) 体力耐力( ...
- [C]为什么发明指针?
指针是C语言中广泛使用的一种数据类型. 运用指针编程是C语言最主要的风格之一.利用指针变量可以表示各种数据结构; 能很方便地使用数组和字符串; 并能象汇编语言一样处理内存地址,从而编出精练而高效的程序 ...
- Struts2 验证码图片实例
本文转载于DongLiYang的博客http://www.cnblogs.com/dongliyang/archive/2012/08/24/2654431.html 其中修改过一部分,针对使用注解而 ...
- Node6.9.2 —— Http官网笔记整理
欢迎指导与讨论 : ) 序章 本文概要:http.Agent代理.http.ClientRequest客户端请求.http.server服务器.http.ServerResponse服务器相应.htt ...
- [LeetCode] Bulls and Cows 公母牛游戏
You are playing the following Bulls and Cows game with your friend: You write a 4-digit secret numbe ...