我知道,那些夏天,就像青春同样回不来。 - 宋冬野
青春是回不来了,却是要准备渡过在西安的第三个夏天了。javascript
我发现,本身对 coding 这件事的称呼,从敲代码
改成 写代码
了。前端
emmm....敲代码,自我感受,就像是,习惯了用 const
定义常量的我看到别人用 var
定义的常量。java
对,优雅!node
写代码
这三个字,显得更为优雅一些,更像是在创做,打磨一件精致的做品。git
改编自 掘金站长
的一句话:程序员
子非猿,安之 coding 之乐也。
最近访问 艾特网 的时候发现请求有点慢。github
后来通过一番检查,发现首页中搜索热点须要每次去爬取百度热搜的数据并当作接口返回给前端,因为是服务端渲染,接口堵塞就容易出现访问较慢的状况。express
就想着对这个接口进行一次重构。npm
1分钟/3分钟/5分钟
爬取新浪微博实时热搜(新浪微博热搜点击率更高一些).json
格式的文件。json
文件的内容需求捋清楚之后就能够开干了。json
首先得找到目标站点,以下:(微博实时热搜)
https://s.weibo.com/top/summary?cate=realtimehot
建立文件夹 weibo
进入文件夹根目录
使用 npm init -y
快速初始化一个项目
建立app.js
文件
安装如下依赖
npm i cherrio superagent -D
关于superagent
和cherrio
的介绍
superagent 是一个轻量级、渐进式的请求库,内部依赖 nodejs 原生的请求 api,适用于 nodejs 环境。cherrio 是 nodejs 的抓取页面模块,为服务器特别定制的,快速、灵活、实施的 jQuery 核心实现。适合各类 Web 爬虫程序。node.js 版的 jQuery。
打开 app.js
,开始完成主要功能
首先在顶部引入cheerio
、superagent
以及 nodejs 中的 fs
模块
const cheerio = require("cheerio"); const superagent = require("superagent"); const fs = require("fs");
经过变量的方式声明热搜的url
,便于后面 复用
const weiboURL = "https://s.weibo.com"; const hotSearchURL = weiboURL + "/top/summary?cate=realtimehot";
使用 superagent
发送get
请求superagent
的 get
方法接收两个参数。第一个是请求的 url
地址,第二个是请求成功后的回调函数。
回调函数有俩参数,第一个参数为 error
,若是请求成功,则返回 null
,反之则抛出错误。第二个参数是请求成功后的 响应体
superagent.get(hotSearchURL, (err, res) => { if (err) console.error(err); });
打开目标站对网页中的 DOM
元素进行一波分析。
对 jQuery
比较熟的小老弟,看到下图如此简洁清晰明了的 DOM
结构,是否是有 N 种取出它每一个 tr
中的数据并 push
到一个 Array
里的方法呢?
对!咱们最终的目的就是要经过 jQuery
的语法,遍历每一个 tr
,并将其每一项的 热搜地址
、热搜内容
、 热度值
、序号
、表情
等信息 push
进一个空数组中
再将它经过 nodejs
的 fs
模块,写入一个 json
文件中。
使用 jQuery
的 each
方法,对 tbody
中的每一项 tr
进行遍历,回调参数中第一个参数为遍历的下标 index
,第二个参数为当前遍历的元素,通常 $(this)
指向的就是当前遍历的元素。
let hotList = []; $("#pl_top_realtimehot table tbody tr").each(function (index) { if (index !== 0) { const $td = $(this).children().eq(1); const link = weiboURL + $td.find("a").attr("href"); const text = $td.find("a").text(); const hotValue = $td.find("span").text(); const icon = $td.find("img").attr("src") ? "https:" + $td.find("img").attr("src") : ""; hotList.push({ index, link, text, hotValue, icon, }); } });
在 nodejs
中,要想向上面那样愉快的写 jQuery
语法,还得将请求成功后返回的响应体,用 cheerio
的 load
方法进行包装。
const $ = cheerio.load(res.text);
接着使用 nodejs
的 fs
模块,将建立好的数组转成 json字符串
,最后写入当前文件目录下的 hotSearch.json
文件中(无此文件则会自动建立)。
fs.writeFileSync( `${__dirname}/hotSearch.json`, JSON.stringify(hotList), "utf-8" );
完整代码以下:
const cheerio = require("cheerio"); const superagent = require("superagent"); const fs = require("fs"); const weiboURL = "https://s.weibo.com"; const hotSearchURL = weiboURL + "/top/summary?cate=realtimehot"; superagent.get(hotSearchURL, (err, res) => { if (err) console.error(err); const $ = cheerio.load(res.text); let hotList = []; $("#pl_top_realtimehot table tbody tr").each(function (index) { if (index !== 0) { const $td = $(this).children().eq(1); const link = weiboURL + $td.find("a").attr("href"); const text = $td.find("a").text(); const hotValue = $td.find("span").text(); const icon = $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" ); });
打开终端,输入 node app
,可看到根目录下多了个 hotSearch.json
文件。
虽然代码能够运行,也能爬取到数据并存入 json 文件。
可是,每次都要手动运行,才能爬取到当前时间段的热搜数据,这一点都 不人性化!
最近微博热搜瓜这么多,咱但是一秒钟可都不能耽搁。咱们最开始指望的是每隔多长时间 定时执行爬取
操做。瓜可不能停!
接下来,对代码进行 小部分改造
。
因为 superagent
请求是个异步方法,咱们能够将整个请求方法用 Promise
封装起来,而后 每隔指定时间
调用此方法便可。
function getHotSearchList() { return new Promise((resolve, reject) => { superagent.get(hotSearchURL, (err, res) => { if (err) reject("request error"); const $ = cheerio.load(res.text); let hotList = []; $("#pl_top_realtimehot table tbody tr").each(function (index) { if (index !== 0) { const $td = $(this).children().eq(1); const link = weiboURL + $td.find("a").attr("href"); const text = $td.find("a").text(); const hotValue = $td.find("span").text(); const icon = $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库
来完成。
https://github.com/node-schedule/node-schedule
先安装
npm i node-schedule -D
头部引入
const nodeSchedule = require("node-schedule");
用法(每分钟的第 30 秒定时执行一次):
const rule = "30 * * * * *"; schedule.scheduleJob(rule, () => { console.log(new Date()); });
规则参数:
* * * * * * ┬ ┬ ┬ ┬ ┬ ┬ │ │ │ │ │ │ │ │ │ │ │ └ day of week (0 - 7) (0 or 7 is Sun) │ │ │ │ └───── month (1 - 12) │ │ │ └────────── day of month (1 - 31) │ │ └─────────────── hour (0 - 23) │ └──────────────────── minute (0 - 59) └───────────────────────── second (0 - 59, OPTIONAL)
6 个占位符从左到右依次表明:秒、分、时、日、月、周几*
表示通配符,匹配任意。当 *
为秒时,表示任意秒都会触发,其余类推。
来看一个 每小时的第20分钟20秒
定时执行的规则:
20 20 * * * *
更多规则自行搭配。
使用定时任务来执行上面的请求数据,写入文件操做:
nodeSchedule.scheduleJob("30 * * * * *", async function () { try { const hotList = await getHotSearchList(); await fs.writeFileSync( `${__dirname}/hotSearch.json`, JSON.stringify(hotList), "utf-8" ); } catch (error) { console.error(error); } });
哦对,别忘了 捕获异常
下面贴上完整代码(可直接 ctrl c/v):
const cheerio = require("cheerio"); const superagent = require("superagent"); const fs = require("fs"); const nodeSchedule = require("node-schedule"); const weiboURL = "https://s.weibo.com"; const hotSearchURL = weiboURL + "/top/summary?cate=realtimehot"; function getHotSearchList() { return new Promise((resolve, reject) => { superagent.get(hotSearchURL, (err, res) => { if (err) reject("request error"); const $ = cheerio.load(res.text); let hotList = []; $("#pl_top_realtimehot table tbody tr").each(function (index) { if (index !== 0) { const $td = $(this).children().eq(1); const link = weiboURL + $td.find("a").attr("href"); const text = $td.find("a").text(); const hotValue = $td.find("span").text(); const icon = $td.find("img").attr("src") ? "https:" + $td.find("img").attr("src") : ""; hotList.push({ index, link, text, hotValue, icon, }); } }); hotList.length ? resolve(hotList) : reject("errer"); }); }); } nodeSchedule.scheduleJob("30 * * * * *", async function () { try { const hotList = await getHotSearchList(); await fs.writeFileSync( `${__dirname}/hotSearch.json`, JSON.stringify(hotList), "utf-8" ); } catch (error) { console.error(error); } });
express
koa
eggjs
或者原生的 nodejs 项目中,做为接口返回给前端。热搜
关键字便可实时获取热搜数据。都看到这里啦,就很棒! 点个赞
再走嘛。
程序员导航站:https://iiter.cn
下面是咱的公众号呀 前端糖果屋
代码 github 已开源: