nodejs–简单爬虫
首先你需要掌握以下内容:
1. 简单的JS基础
2. 了解过函数式编程
3. jquery选择器
本文的运行环境:
- windows10
- 已经安装好nodejs
有关nodejs的安装请自行百度,这里不做过多的介绍
正文
首先安装好以下模块
- eventproxy
- cheerio
- async
(关于async我的代码有一个问题,之后会说明,请大神帮忙看下,告诉我为什么,谢谢)
首先写一个方法用来获取目标HTML文本
var http = require('http');
var async = require('async');
var cheerio = require('cheerio');
var url = require('url');
var eventproxy = require('eventproxy');
//指定网页URL
var urlAddress = "http://tieba.baidu.com/f?kw=c%23&fr=home";
var down = function (url,callback){
http.get(url,function(res){
var data = "";
//读取文件流
//有关request的使用方式不懂的朋友可以去官网看看
//https://github.com/mikeal/request
res.on('data',function(chunk){
data += chunk;
});
res.on('end',function(){
callback(data);
});
}
).on('error',function(){
callback(null)
});
}
好了,上面的代码就算一个小小的爬虫了。(一根筋的小蜘蛛)
down(urlAddress,function(data){
//判断下是否成功获取到HTML文本
if(data){
console.log(data);
}else{
console.log("error");
}
});
以上的代码是down函数的调用示例,获取到HTML文本后直接输出,如果失败的输出error
下面我们就来使用下cheerio和eventproxy模块
//先抓取页面,然后分析出里面帖子的地址,存到数组里
var topicUrls = [];
//标题头
var urlAdd = "http://tieba.baidu.com";
//这里我们调用down方法,让小蜘蛛消化下HTML文本
//然后生下更多的小蜘蛛去爬更多的页面
down(urlAddress ,function(data){
//和jquery一样的用法
var $ = cheerio.load(data);
//如果class包含.j_th_tit并且在a标签下则执行该函数
$('a.j_th_tit').each(function (idx, element) {
var $element = $(element);
//利用url拼接标题头和获取到的链接
//也可以写成 var href = urlAdd + $element.attr('href');
var href = url.resolve(urlAdd,$element.attr('href'));
//将链接放进数组里
topicUrls.push(href);
});
//这里我们输出下获取到的链接数量
console.log(topicUrls.length);
var ep = new eventproxy();
//循环数组并为每一个元素执行一次函数
topicUrls.forEach(function(item){
//获取链接的HTML文本
down(item,function(data){
//添加html_load事件
ep.emit('html_load',data);
});
});
//添加计数器
var time = 0;
//after是当事件达到10次时执行
ep.after('html_load',10,function(data){
//循环数组
data.forEach(function(data){
var $2 = cheerio.load(data);
var first = "";
//读取第一条符合条件的文本
$2('div.d_post_content').first().each(function (idx, element) {
var $element = $(element);
time = time + 1;
first = time + ':' + $element.text();
});
//输出文本
console.log(first);
});
});
});
贴出完整的代码
var http = require('http');
var async = require('async');
var cheerio = require('cheerio');
var url = require('url');
var eventproxy = require('eventproxy');
var urlAddress = "http://tieba.baidu.com/f?kw=c%23&fr=home";
var down = function (url,callback){
http.get(url,function(res){
var data = "";
res.on('data',function(chunk){
data += chunk;
});
res.on('end',function(){
callback(data);
});
}
).on('error',function(){
callback(null)
});
}
//先抓取页面,然后分析出里面帖子的地址,存到数组里
var topicUrls = [];
var urlAdd = "http://tieba.baidu.com";
down(urlAddress ,function(data){
var $ = cheerio.load(data);
$('a.j_th_tit').each(function (idx, element) {
var $element = $(element);
var href = url.resolve(urlAdd,$element.attr('href'));
topicUrls.push(href);
});
console.log(topicUrls.length);
var ep = new eventproxy();
topicUrls.forEach(function(item){
down(item,function(data){
ep.emit('html_load',data);
});
});
var time = 0;
ep.after('html_load',10,function(data){
data.forEach(function(data){
var $2 = cheerio.load(data);
var first = "";
$2('div.d_post_content').first().each(function (idx, element) {
var $element = $(element);
time = time + 1;
first = time + ':' + $element.text();
});
console.log(first);
});
});
});
以上就是一个简单的爬虫
里面用了一个并发事件,一次发出10条请求,个人觉得不妥,于是就用了ascyn,但是还不习惯异步思想,所以有一个问题无法解决。请大家看看,指点迷津
下面贴出代码
var http = require('http');
var async = require('async');
var cheerio = require('cheerio');
var url = require('url');
var eventproxy = require('eventproxy');
var urlAddress = "http://tieba.baidu.com/f?kw=c%23&fr=home";
var down = function (url,callback){
http.get(url,function(res){
var data = "";
res.on('data',function(chunk){
data += chunk;
});
res.on('end',function(){
callback(data);
});
}
).on('error',function(){
callback(null)
});
}
//先抓取页面,然后分析出里面帖子的地址,存到数组里
var topicUrls = [];
var urlAdd = "http://tieba.baidu.com";
down(urlAddress ,function(data){
var $ = cheerio.load(data);
$('a.j_th_tit').each(function (idx, element) {
var $element = $(element);
var href = url.resolve(urlAdd,$element.attr('href'));
topicUrls.push(href);
});
console.log(topicUrls.length);
var time = 0;
//这里只执行了5次,我个人的想法是每次5条请求,最后一共执行
//topicUrls.length条
//我个人分析下觉得是执行完5次后,down函数结束了,顺带着把async也关了
//但是异步的话应该async是独立的函数,不应该受到影响才对
//请大家帮忙指点下
async.forEachLimit(topicUrls,5,function(item, callback){
down(item,function(data){
var $ = cheerio.load(data);
$('div.d_post_content').first().each(function (idx, element) {
var $element = $(element);
time = time + 1;
console.log(time + ':' + $element.text());
});
});
},function(err){
console.log('错误:' + err);
});
});