夏天来了我知道,那些夏天,就像青春一样,回不来了。——宋冬野的青春一去不复返,他却即将在西安度过第三个夏天。废话,我发现我对coding的称呼已经从敲代码变成写代码了。emmm....敲代码,感觉,习惯用const定义常量,看到别人用var定义的常量。是的,优雅!写代码三个字更优雅,更像是创造和打磨一件精致的作品。改编自掘金站长的一句话:子不是猿,暗指是编码的乐趣。看了这篇文章的结果,ctrl+cctrl+vnodejs为什么入门级爬虫写爬虫相关的文章最近访问iTec的时候,发现请求有点慢。后来经过一番排查,发现首页的搜索热点每次都需要爬取百度热搜数据,作为接口返回给前端。因为是服务端渲染的,界面阻塞,访问容易出现访问缓慢的情况。只想重构这个接口。解决方法是设置定时任务,每隔1分钟/3分钟/5分钟爬取新浪微博实时热搜(新浪微博热搜点击率较高)。爬取完数据后,并不会直接返回给前端,而是先写入一个.json格式的文件。服务器端渲染后台接口请求和返回给前端json文件的内容需求明确后,就可以开始了。创建项目初始化首先要找到目标站点,如下:(微博实时热搜)https://s.weibo.com/top/summary?cate=realtimehot创建文件夹weibo,进入根目录文件夹目录下,使用npminit-y快速初始化一个项目安装依赖创建app.js文件安装如下依赖npmicherriosuperagent-Dsuperagent简介cherriosuperagent是一个轻量级的渐进式请求库,内部依赖nodejs原生请求api,适合nodejs环境。cherrio是一个nodejs爬取页面模块,一个快速、灵活、可实现的jQuery核心实现,专门为服务端定制。适用于各种网络爬虫。用于node.js的jQuery。代码编写打开app.js,开始完成主要功能首先导入cheerio、superagent和最上面nodejs中的fs模块constcheerio=require("cheerio");constsuperagent=require("superagent");constfs=要求(“fs”);通过变量的方式声明热搜url,方便后面复用requestusingsuperagentsuperagent的get方法接受两个参数。第一个是请求的url地址,第二个是请求成功后的回调函数。回调函数有两个参数,第一个参数为error,如果请求成功则返回null,否则会抛出错误。第二个参数是响应体superagent.get(hotSearchURL,(err,res)=>{if(err)console.error(err);});网页元素解析打开目标站点的DOM,对网页元素进行一波解析。熟悉jQuery的朋友,看到下图简洁明了的DOM结构,是不是有N种方法可以将每个tr中的数据提取出来,压入一个Array中呢?正确的!我们的最终目的是通过jQuery的语法遍历每一个tr,将每一个item的热搜地址、热搜内容、热度值、序号、表情等信息push到一个空数组中,然后通过nodejs传递给fs该文件的模块被写入一个json文件。jQuery遍历取出数据,使用jQuery的each方法遍历tbody中的每一项tr。回调参数中第一个参数是遍历的下标索引,第二个参数是当前正在遍历的元素。一般$(this)指向当前遍历的元素。lethotList=[];$("#pl_top_realtimehottabletbodytr").each(function(index){if(index!==0){const$td=$(this).children().eq(1)};constlink=weiboURL+$td.find("a").attr("href");consttext=$td.find("a").text();consthotValue=$td.find("span").text();consticon=$td.find("img").attr("src")?"https:"+$td.find("img").attr("src"):"";hotList.push({index,link,text,hotValue,icon,});}});cheerio包装请求后的响应主体在nodejs中。成功后返回的responsebody用cheerio的load方法打包。const$=cheerio.load(res.text);编写json文件,然后使用nodejs的fs模块将创建的数组转换为json字符串,最后写入当前文件目录下的hotSearch.json文件(不会自动创建该文件)。fs.writeFileSync(`${__dirname}/hotSearch.json`,JSON.stringify(hotList),"utf-8");完整代码如下:constcheerio=require("cheerio");constsuperagent=require("superagent");constfs=require("fs");constweiboURL="https://s.weibo.com";consthotSearchURL=weiboURL+"/top/summary?cate=realtimehot";superagent.get(hotSearchURL,(err,res)=>{if(err)console.error(err);const$=cheerio.load(res.text);lethotList=[];$("#pl_top_realtimehottabletbodytr").each(function(index){if(index!==0){const$td=$(this).children().eq(1);constlink=weiboURL+$td.find("a").attr("href");consttext=$td.find("a").text();consthotValue=$td.find("span").text();consticon=$td.find("img").attr("src")?"https:"+$td.find("img").attr("src"):"";hotList.push({index,link,text,hotValue,icon,});}});fs.writeFileSync(`${__dirname}/hotSearch.json`,JSON.stringify(hotList),"utf-8");});打开终端,进入nodeapp,可以看到根目录下多了一个hotSearch.json文件。虽然代码可以定时运行,但也可以抓取数据,存储在json文件中。但是每次爬取当前时间段的热搜数据都得手动运行,一点都不人性化!最近微博热搜太多了,一秒钟也不能耽搁。我们最初期望的是定期执行爬取操作的频率。瓜停不下来!接下来,对代码做一个小的修改。数据请求封装由于superagent请求是一个异步方法,我们可以把整个请求方法用Promise封装起来,然后每隔指定的时间调用这个方法。functiongetHotSearchList(){returnnewPromise((resolve,reject)=>{superagent.get(hotSearchURL,(err,res)=>{if(err)reject("requesterror");const$=cheerio.load(res.text);lethotList=[];$("#pl_top_realtimehottabletbodytr").each(function(index){if(index!==0){const$td=$(this).children()}.eq(1);constlink=weiboURL+$td.find("a").attr("href");consttext=$td.find("a").text();consthotValue=$td.find("span").text();consticon=$td.find("img").attr("src")?"https:"+$td.find("img").attr("src"):"";hotList.push({index,link,text,hotValue,icon,});}});hotList.length?resolve(hotList):reject("errer");});});}node-schedule定时任务详解我们可以使用nodejs库node-schedule来完成。https://github.com/node-schedule/node-schedule首先安装npminode-schedule-Dheader引入constnodeSchedule=require("node-schedule");):construle="30*****";schedule.scheduleJob(rule,()=>{console.log(newDate());});规则参数:******┬┬┬┬│││││││││││└星期几(0-7)(0或7是星期日)││││└────月(1-12)│││└──────────月中的第几天(1-31)││└──────────────────小时(0-23)│└────────────────────────────────分钟(0-59)└────────────────────────────────────第二(0-59,可选)6个占位符代表从左到right:second,minute,hour,day,month,dayoftheweek*表示通配符,匹配any。当*为秒时,表示任何一秒都会触发,以此类推。我们来看一个定时在每小时20分20秒执行的规则:2020****更多的规则可以自己匹配。定时爬取,写文件使用定时任务执行上述请求数据,写文件操作:nodeSchedule.scheduleJob("30*****",asyncfunction(){writeFileSync(`${__dirname}/hotSearch.json`,JSON.stringify(hotList),"utf-8");}catch(error){console.error(error);}});哦,是的,不要忘记将完整代码粘贴到catch异常下方(直接ctrlc/v):constcheerio=require("cheerio");constsuperagent=require("superagent");constfs=require("fs");constnodeSchedule=require("node-schedule");constweiboURL="https://s.weibo.com";consthotSearchURL=weiboURL+"/top/summary?cate=realtimehot";functiongetHotSearchList(){returnnewPromise((resolve,reject)=>{superagent.get(hotSearchURL,(err,res)=>{if(err)reject("requesterror");const$=cheerio.load(res.text);lethotList=[];$("#pl_top_realtimehottabletbodytr").each(function(index){if(index!==0){const$td=$(this).children().eq(1);constlink=weiboURL+$td.find("a").attr("href");consttext=$td.find("a").text();consthotValue=$td.find("span").text();consticon=$td.find("img").attr("src")?"https:"+$td.find("img").attr("src"):"";hotList.push({index,link,text,hotValue,icon,});}});hotList.length?解决(热门列表):拒绝(“错误”);});});}nodeSchedule.scheduleJob("30*****",asyncfunction(){try{consthotList=awaitgetHotSearchList();awaitfs.writeFileSync(`${__dirname}/hotSearch.json`,JSON.stringify(hotList),"utf-8");}catch(error){console.error(error);}});各种玩法以上代码可以直接集成到已有的expresskoaeggjs或者nativenodejs项目中,作为接口返回给前端集成Serverless,作为接口返回给前端。连接微信公众号,发送热搜关键词,实时获取热搜数据。融入微信机器人,每天指定时间向自己/群发送微博热搜数据。其他……看到这里,太棒了!给它一个大拇指,让我们走吧。程序员导航站:https://iiter.cn这里是我们的公众号!前端糖果屋代码github已经开源:https://github.com/isnl/weibo-hotSearch-crawler
