五、nodejs使用 eventproxy 控制并发

目标

爬取 CNode(https://cnodejs.org/) 社区首页的标题和详情页的第一条评论,以及评论的作者,作者积分,最后以json格式打印

步骤

注意:很多网站有并发连接数的限制,所以当请求发送太快的时候会导致返回值为空或报错。

安装依赖 express superagent cheerio eventproxy

$ npm install express superagent cheerio eventproxy --save

新建app.js 抓取所有的url

// 引入依赖
var express = require('express');
var eventproxy = require('eventproxy');
var superagent = require('superagent');
var cheerio = require('cheerio');

var app = express();

// url 模块是 Node.js 标准库里面的
var url = require('url');

var cnodeUrl = 'https://cnodejs.org/';

app.get('/', function(req, res, next) {
    // 用 superagent 去抓取 https://cnodejs.org/ 的内容
    superagent.get(cnodeUrl)
        .end(function(err, sres) {
            if (err) {
                return next(err);
            }
            // sres.text 里面存储着网页的 html 内容,将它传给 cheerio.load 之后,就可以得到一个实现了 jquery 接口的变量,我们习惯性地将它命名为 `$`
            // 剩下就都是 jquery 的内容了
            var $ = cheerio.load(sres.text);
            
            var topicUrls = [];
            // 获取所有链接
            $('#topic_list .topic_title').each(function(index, elem) {
                var $element = $(elem);

                // url.resolve 来自动推断出完整 url
                var href = url.resolve(cnodeUrl, $element.attr('href'));
                topicUrls.push(href);
            });

            res.send(topicUrls);
        });
});

app.listen(3000, function (req, res) {
    console.log('app is running at port 3000');
});

运行node app.js

eventproxy
var ep = new eventproxy();
ep.all('data1_event', 'data2_event', 'data3_event', function (data1, data2, data3) {
  var html = fuck(data1, data2, data3);
  render(html);
});

$.get('http://data1_source', function (data) {
  ep.emit('data1_event', data);
  });

$.get('http://data2_source', function (data) {
  ep.emit('data2_event', data);
  });

$.get('http://data3_source', function (data) {
  ep.emit('data3_event', data);
  });

ep.all('data1_event', 'data2_event', 'data3_event', function (data1, data2, data3) {});

这一句,监听了三个事件,分别是 data1_event, data2_event, data3_event,每次当一个源的数据抓取完成时,就通过 ep.emit() 来告诉 ep 自己,某某事件已经完成了。

当三个事件未同时完成时,ep.emit() 调用之后不会做任何事;当三个事件都完成的时候,就会调用末尾的那个回调函数,来对它们进行统一处理。

详细
// 引入依赖
var express = require('express');
var eventproxy = require('eventproxy');
var superagent = require('superagent');
var cheerio = require('cheerio');
// url 模块是 Node.js 标准库里面的
var url = require('url');

var app = express();
var ep = new eventproxy(); // 得到一个 eventproxy 的实例


var cnodeUrl = 'https://cnodejs.org/';

app.get('/', function(req, res, next) {
    // 用 superagent 去抓取 https://cnodejs.org/ 的内容
    superagent.get(cnodeUrl)
        .end(function(err, sres) {
            if (err) {
                return next(err);
            }
            // sres.text 里面存储着网页的 html 内容,将它传给 cheerio.load 之后,就可以得到一个实现了 jquery 接口的变量,我们习惯性地将它命名为 `$`
            // 剩下就都是 jquery 的内容了
            var $ = cheerio.load(sres.text);
            
            var topicUrls = [];
            // 获取所有链接
            $('#topic_list .topic_title').each(function(index, elem) {
                var $element = $(elem);

                // url.resolve 来自动推断出完整 url
                var href = url.resolve(cnodeUrl, $element.attr('href'));
                topicUrls.push(href);
            });

            // 命令 ep 重复监听 topicUrls.length 次(在这里也就是 40 次) `topic_html` 事件再行动
            ep.after('topic_html', topicUrls.length, function(topics) {
                // topics 是个数组,包含了 40 次 ep.emit('topic_html', pair) 中的那 40 个 pair

                topics = topics.map(function(topicpair) {
                    var topicUrl = topicpair[0];
                    var topicHtml = topicpair[1];
                    var $ = cheerio.load(topicHtml);
                    return ({
                        title: $('.topic_full_title').text().trim(),
                        href: topicUrl,
                        comment: $('.reply_content').eq(0).text().trim(),
                    });
                });
                
                res.send(topics);
            })

            topicUrls.forEach(function(topicUrl) {
                superagent.get(topicUrl)
                    .end(function(uerr, ures) {
                        console.log('success:' + topicUrl);
                        ep.emit('topic_html', [topicUrl, ures.text]);
                    });
            });
        });
});

app.listen(3000, function (req, res) {
    console.log('app is running at port 3000');
});

转载于:https://my.oschina.net/u/3913691/blog/3061198

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值