nodeJS完成基于Promise爬虫 定时发送信息到指定邮件

英国人Robert Pitt曾在Github上宣布了他的爬虫剧本,致使任何人都能够容易地获得Google Plus的大批公然用户的ID信息。至今大概有2亿2千5百万用户ID遭暴光。

亮点在于,这是个nodejs剧本,异常短,包含解释只要71行。

毫无疑问,nodeJS改变了全部前端开辟生态。本文一步步完成了一个基于promise的nodeJS爬虫顺序,收集简书恣意指定作者的文章信息。并终究把爬下来效果以邮件的情势,自动化发给目标对象。万万不要被nodeJS的表面吓到,既是你是初入前端的小菜鸟,或是刚打仗nodeJS不久的新同砚,都不阻碍对这篇文章的阅读和明白。

爬虫的一切代码能够在我的Github堆栈找到,往后这个爬虫顺序还会举行不停晋级和更新,迎接关注。

nodeJS VS Python完成爬虫

我们先从爬虫提及。对照一下,议论为何nodeJS合适/不合适作为爬虫编写言语。
起首,总结一下:

NodeJS单线程、事宜驱动的特征能够在单台机械上完成极大的吞吐量,异常合适写收集爬虫这类资本密集型的顺序。

然则,关于一些庞杂场景,须要越发周全的斟酌。以下内容总结自知乎相干题目,谢谢@知乎网友,对答案的孝敬。

  • 假如是定向爬取几个页面,做一些简朴的页面剖析,爬取效力不是中心要求,那末用什么言语差别不大。

  • 假如是定向爬取,且重要目标是剖析js动态天生的内容 :
    此时,页面内容是由js/ajax动态天生的,用一般的要求页面+剖析的要领就不管用了,须要借助一个相似firefox、chrome阅读器的js引擎来对页面的js代码做动态剖析。

  • 假如爬虫是触及大规模网站爬取,效力、扩展性、可保护性等是必需斟酌的要素时刻:
    大规模爬虫爬取触及诸多题目:多线程并发、I/O机制、分布式爬取、音讯通信、判重机制、使命调理等等,此时刻言语和所用框架的拔取就具有极大意义了。详细来看:

PHP:对多线程、异步支撑较差,不发起采纳。
NodeJS:对一些垂直网站爬取倒能够。但因为分布式爬取、音讯通信等支撑较弱,依据本身状况推断。
Python:发起,对以上题目都有较好支撑。

固然,我们本日所完成的是一个浅易爬虫,不会对目标网站带来任何压力,也不会对个人隐私形成不好影响。毕竟,他的目标只是熟习nodeJS环境。适用于新人入门和练手。

固然,任何歹意的爬虫性子是卑劣的,我们应当尽力防备影响,配合保护收集环境的康健。

爬虫实例

本日要编写的爬虫目标是爬取简书作者:LucasHC(我本人)在简书平台上,宣布过的一切文章信息,包含:每篇文章的:

  • 宣布日期;

  • 文章字数;

  • 批评数;

  • 阅读数、赞扬数;
    等等。

终究爬取效果的输出以下:

《nodeJS完成基于Promise爬虫 定时发送信息到指定邮件》

以下效果,我们须要经由过程剧本,自动地发送邮件到指定邮箱。收件内容以下:

《nodeJS完成基于Promise爬虫 定时发送信息到指定邮件》

以上效果只须要一键操纵便可完成。

爬虫设想

我们的顺序一共依靠三个模块/类库:

const http = require("http");
const Promise = require("promise");
const cheerio = require("cheerio");

发送要求

http是nodeJS的原生模块,本身就能够用来构建效劳器,而且http模块是由C++完成的,机能牢靠。
我们运用Get,来要求简书作者相干文章的对应页面:

http.get(url, function(res) {
    var html = "";
    res.on("data", function(data) {
        html += data;
    });

    res.on("end", function() {
        ...
    });
}).on("error", function(e) {
    reject(e);
    console.log("猎取信息失足!");
});

因为我发明,简书中每一篇文章的链接情势以下:
完全情势:“http://www.jianshu.com/p/ab27…”,
即 “http://www.jianshu.com/p/” + “文章id”。

所以,上述代码中相干作者的每篇文章url:由baseUrl和相干文章id拼接构成:

articleIds.forEach(function(item) {
    url = baseUrl + item;
});

articleIds自然是存储作者每篇文章id的数组。

终究,我们把每篇文章的html内容存储在html这个变量中。

异步promise封装

因为作者能够存在多篇文章,所以关于每篇文章的猎取和剖析我们应当异步举行。这里我运用了promise封装上述代码:

function getPageAsync (url) {
    return new Promise(function(resolve, reject){
        http.get(url, function(res) {
            ...
        }).on("error", function(e) {
            reject(e);
            console.log("猎取信息失足!");
        });
    });
};

如许一来,比方我写过14篇原创文章。如许对每一片文章的要乞降处置惩罚全都是一个promise对象。我们存储在预先定义好的数组当中:

const articlePromiseArray = [];

接下来,我运用了Promise.all要领举行处置惩罚。

Promise.all要领用于将多个Promise实例,包装成一个新的Promise实例。

该要领接收一个promise实例数组作为参数,实例数组中一切实例的状况都变成Resolved,Promise.all返回的实例才会变成Resolved,并将Promise实例数组的一切返回值构成一个数组,传递给回调函数。

也就是说,我的14篇文章的要求对应14个promise实例,这些实例都要求终了后,实行以下逻辑:

Promise.all(articlePromiseArray).then(function onFulfilled (pages) {
    pages.forEach(function(html) {
        let info = filterArticles(html);
        printInfo(info);        
    });
}, function onRejected (e) {
    console.log(e);
});

他的目标在于:对每个返回值(这个返回值为单篇文章的html内容),举行filterArticles要领处置惩罚。处置惩罚所得效果举行printInfo要领输出。
接下来,我们看看filterArticles要领做了什么。

html剖析

实在很明显,假如您明白了上文的话。filterArticles要领就是对单篇文章的html内容举行有价值的信息提取。这里有价值的信息包含:
1)文章题目;
2)文章宣布时候;
3)文章字数;
4)文章阅读量;
5)文章批评数;
6)文章赞扬数。

function filterArticles (html) {
    let $ = cheerio.load(html);
    let title = $(".article .title").text();
    let publishTime = $('.publish-time').text();
    let textNum = $('.wordage').text().split(' ')[1];
    let views = $('.views-count').text().split('阅读')[1];
    let commentsNum = $('.comments-count').text();
    let likeNum = $('.likes-count').text();

    let articleData = {
        title: title,
        publishTime: publishTime,
        textNum: textNum
        views: views,
        commentsNum: commentsNum,
        likeNum: likeNum
    }; 
    
    return articleData;
};

你或许会新鲜,为何我能运用相似jQuery中的$对html信息举行操纵。实在这归功于cheerio类库。

filterArticles要领返回了每篇文章我们感兴趣的内容。这些内容存储在articleData对象当中,终究由printInfo举行输出。

邮件自动发送

到此,爬虫的设想与完成到了一段落。接下来,就是把我们爬取的内容以邮件体式格局举行发送。
这里我运用了nodemailer模块举行发送邮件。相干逻辑放在Promise.all当中:

Promise.all(articlePromiseArray).then(function onFulfilled (pages) {
    let mailContent = '';
    var transporter = nodemailer.createTransport({
        host : 'smtp.sina.com',
        secureConnection: true, // 运用SSL体式格局(平安体式格局,防备被窃取信息)
        auth : {
            user : '**@sina.com',
            pass : ***
        },
    });
    var mailOptions = {
        // ...
    };
    transporter.sendMail(mailOptions, function(error, info){
        if (error) {
            console.log(error);
        }
        else {
            console.log('Message sent: ' + info.response);
        }
    });
}, function onRejected (e) {
    console.log(e);
});

邮件效劳的相干设置内容我已举行了恰当隐蔽。读者能够自行设置。

总结

本文,我们一步一步完成了一个爬虫顺序。触及到的知识点重要有:nodeJS基础模块用法、promise观点等。假如拓展下去,我们还能够做nodeJS衔接数据库,把爬取内容存在数据库当中。固然也能够运用node-schedule举行定时剧本掌握。固然,现在这个爬虫目标在于入门,完成还相对浅易,目标源并非大型数据。

本文只触及nodeJS的冰山一角,愿望人人一同探究。假如你对完全代码感兴趣,请点击这里。

Happy Coding!

    原文作者:lucas_580e331d326b4
    原文地址: https://segmentfault.com/a/1190000008880069
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞