当前位置: 首页 > 后端技术 > Node.js

nodeJS实现了一个基于Promise的爬虫,定时发送信息到指定邮箱

时间:2023-04-03 18:59:34 Node.js

英国人RobertPitt曾在Github上发布了他的爬虫脚本,让任何人都可以轻松获取Google+大量公众用户的ID信息.到目前为止,已经暴露了大约2.25亿个用户ID。亮点是这是一个nodejs脚本,非常短,包括注释只有71行。毫无疑问,nodeJS改变了整个前端开发生态。本文一步一步完成了一个基于promise的nodeJS爬虫程序,用于收集简书任意指定作者的文章信息。最后,攀爬结果以邮件的形式自动发送给目标对象。不要被nodeJS的出现吓倒了。哪怕你是一个刚接触前端的菜鸟,或者是刚接触nodeJS的新同学,也不妨碍阅读和理解本文。爬虫的所有代码都可以在我的Github仓库中找到。今后,本爬虫程序将不断升级更新。欢迎关注。NodeJSVSPython实现爬虫先从爬虫说起。对比一下,讨论为什么nodeJS适合/不适合作为爬虫编写语言。首先总结一下:NodeJS单线程、事件驱动的特性可以在单机上实现很大的吞吐量,非常适合编写网络爬虫等资源密集型程序。但是,对于一些复杂的场景,需要更全面的考虑。以下内容总结了知乎的相关问题。感谢@知识网络对答案的贡献。如果是有针对性的抓取几个页面,做一些简单的页面分析,抓取效率不是核心需求,那么使用的语言差别不大。如果是定向爬取,主要目标是解析js动态生成的内容:这时候页面内容是js/ajax动态生成的,普通的请求页面+解析的方式就不行了。需要使用类似firefox,chrome浏览器的js引擎动态解析页面的js代码。如果爬虫涉及到大型网站爬取,效率、可扩展性、可维护性等都是必须考虑的因素:大型爬虫爬取涉及到很多问题:多线程并发、I/O机制、分布式爬取、消息通信、判断机制、任务调度等。此时,所使用的语言和框架的选择就具有重要意义。具体来说:PHP:对多线程和异步的支持较差,不推荐。NodeJS:可以爬取一些垂直网站。但是由于对分布式爬取和消息通信的支持较弱,根据自己的情况判断。Python:建议,对上述问题有很好的支持。当然,我们今天实现的是一个简单的爬虫,不会给目标网站带来任何压力,也不会对个人隐私造成不良影响。毕竟他的目的只是为了熟悉一下nodeJS的环境。适合新手入门和练习。当然,任何恶意爬虫的本质都是不好的,我们应该尽量避免影响,共同维护网络环境的健康。爬虫示例今天要写的爬虫目的是爬取简书作者:LucasHC(本人)在简书平台发表的所有文章信息,包括:每篇文章:发表日期;文章中的字数;评论数量;观看次数、欣赏次数;等等。最终爬取结果的输出如下:针对如下结果,我们需要通过脚本自动发送邮件到指定邮箱。收据内容如下:以上结果可通过一键操作完成。爬虫设计我们的程序依赖于三个模块/类库:consthttp=require("http");constPromise=require("承诺");constcheerio=require("cheerio");发送请求http是nodeJS的native模块,可以自己搭建服务器,http模块是用C++实现的,性能可靠。我们使用Get请求简书作者相关文章的对应页面:http.get(url,function(res){varhtml="";res.on("data",function(data){html+=data;});res.on("end",function(){...});}).on("error",function(e){reject(e);console.log("获取错误information!");});因为我发现简书每篇文章的链接形式如下:完整形式:“http://www.jianshu.com/p/ab27...”,即就是,“http://www.jianshu.com/p/”+“文章id”。因此,上述代码中相关作者每篇文章的url:由baseUrl和相关文章的id组成:articleIds.forEach(function(item){url=baseUrl+item;});articleIds自然存放的是author数组每篇文章的id。最后我们将每篇文章的html内容存放在变量html中。异步promise封装由于作者可能有多篇文章,我们应该异步获取并解析每篇文章。这里我用promise封装了上面的代码:functiongetPageAsync(url){returnnewPromise(function(resolve,reject){http.get(url,function(res){...}).on("error",function(e){reject(e);console.log("获取信息时出错!");});});};就这样,比如我写了14篇原创文章。这样每篇文章的请求和处理都是一个promise对象。我们将它存储在一个预定义的数组中:constarticlePromiseArray=[];接下来,我使用Promise.all方法进行处理。Promise.all方法用于将多个Promise实例包装成一个新的Promise实例。此方法接受一组promise实例作为参数。实例数组中所有实例的状态变为Resolved,Promise.all返回的实例变为Resolved。Promise实例数组的所有返回值组成一个数组传递给回调函数。也就是说我请求的14篇文章对应14个promise实例。在请求所有这些实例之后,将执行以下逻辑:});},函数onRejected(e){console.log(e);});他的目的是:对于每一个返回值(这个返回值为单篇文章的html内容),都使用filterArticles方法进行处理。处理得到的结果由printInfo方法输出。接下来,让我们看看filterArticles方法做了什么。如果您了解以上内容,HTML解析实际上非常明显。filterArticles方法是从单篇文章的html内容中提取有价值的信息。这里有价值的信息包括:1)文章标题;2)文章发表时间;3)文章字数统计;4)文章浏览量;5)文章评论编号;6)文章鉴赏数。functionfilterArticles(html){让$=cheerio.load(html);让标题=$(".article.title").text();让publishTime=$('.publish-time').text();让textNum=$('.wordage').text().split('')[1];让views=$('.views-count').text().split('reading')[1];让commentsNum=$('.comments-count').text();让likeNum=$('.likes-count').text();让articleData={title:title,publishTime:publishTime,textNum:textNumviews:views,commentsNum:commentsNum,likeNum:likeNum};返回文章数据;};你可能想知道为什么我可以在jQuery中使用$来操作html信息。其实这要归功于cheerio类库。filterArticles方法为每篇文章返回我们感兴趣的内容。这些内容存储在articleData对象中,最后由printInfo输出。邮件自动发送到这里,爬虫的设计和实现就到了一个阶段。下一步是通过电子邮件发送我们抓取的内容。这里我使用nodemailer模块来发送邮件。相关逻辑放在Promise.all中:Promise.all(articlePromiseArray).then(functiononFulfilled(pages){letmailContent='';vartransporter=nodemailer.createTransport({host:'smtp.sina.com',secureConnection:true,//使用SSL模式(防止信息被窃取的安全方式)auth:{user:'**@sina.com',pass:***},});varmailOptions={//..。},函数onRejected(e){console.log(e);});我已经妥善隐藏了邮件服务的相关配置内容。读者可自行配置。综上所述,我们一步步实现了一个爬虫程序。涉及到的知识点主要包括:nodeJS基础模块使用、promise概念等,如果继续扩展,我们还可以使用nodeJS连接数据库,将爬取到的内容存储到数据库中。当然你也可以使用node-schedule进行定时脚本控制。当然,目前这个爬虫的目的是入门,实现起来比较简单,目标源也不是大数据。本文只是触及了nodeJS的冰山一角,希望大家一起探讨。如果您对完整代码感兴趣,请单击此处。快乐编码!