5、nodejs使用 eventproxy 控制併發

目標

爬取 CNode(https://cnodejs.org/) 社區首頁的標題和詳情頁的第一條評論,以及評論的做者,做者積分,最後以json格式打印html

步驟

注意:不少網站有併發鏈接數的限制,因此當請求發送太快的時候會致使返回值爲空或報錯。node

安裝依賴 express superagent cheerio eventproxyjquery

$ npm install express superagent cheerio eventproxy --save

新建app.js 抓取全部的urlexpress

// 引入依賴
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.jsnpm

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) {});json

這一句,監聽了三個事件,分別是 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');
});

相關文章
相關標籤/搜索