这份nodejs实现的定时爬取微博热搜程序,请查收!
The summer is coming
”
我知道,那些夏天,就像芳华相同回不来。 – 宋冬野
芳华是回不来了,却是要预备渡过在西安的第三个夏天了。
废话
我发现,自己对 coding 这件事的称号,从敲代码
改为 写代码
了。
emmm….敲代码,自i x R P 0 {我感} Z . )觉,就像是,习惯了用 const
界说常量的我看到他人用 var
界说的常量。
对,高雅!
写代码
这三个字,显得更为高雅一些,更像是在创造,打磨一件精美的作品。
改编自 掘金站长
的一句话:
”
子非猿,安之 coding 之乐也。
看完本文的收获
-
ctrl/ V 5 ] m m + c -
ctrl + v -
nodejs 入门级爬虫
为何写爬虫相关的文章
最近拜访 艾特网 的时候发现恳求有点慢。
后来经过一番查看,发现首页中搜索热点需求每次去爬取百度热搜的数据并作为接口回来给前端,由所以服务端烘托,接口阻塞就简单出现拜访较慢的状况。
就想着对这个接口进行^ ] | = H o G一次重构。
解决方案
-
设置守时使命,每隔 1分钟/3分钟/5分钟
爬取新浪微博实时热搜(新浪微博热搜点v ! $ H : % = _击率更高一些) -
爬取到数据后不直接回来给前端,先写入一个 .json
格式的文件。 -
服务端烘托的后台接口恳求并回来给前端 json
文件的内容V G o
需求捋清楚以后就能够开干了。
创~ 4 3 r p建工程
初始化
首先得找到方针站点,如下:(微博实时热搜)
s.weibo.com/top/suB , ,mmaryG ~ 9…
创t 8 s }建文件夹 weibon k v Z e
进入文件夹根目录
运i Q + +用 npm ini; O @ a gt -y
快速初D | % D c ^ M N始化一个项目
装置依靠
创建app.js
文件
装置以下q Y # W Q 5 y 3依靠
npm i cheerio superagent -D
关于superage{ ^ 2 n :nt
和cheerio
的介绍I _ , (
”
superagent 是一个轻量级、渐进式的恳求库,内部依靠 nodejs 原生的恳求 api,适用于 nodejs 环境。
”
cheerio 是 nodejs 的抓取页面模块,为服务器特别定制的,快速、灵敏、实施的 jQuery 核心实现。合适各种 Web 爬虫程序。node.js 版的 jQuery。
代码编写
打开 a~ f b | opp.js
,开端完结主要功能Q w E ( = `
首先在顶部引入cheerio
、superagent
以及 nodejs 中的 fs
模块
const cheerig X . ^o = require("cheerio");
const superagent = require("superagentl @ 8 r # b 8 [ b");
const fs = require("fs");
经过变量的办8 ) c d J法声明热搜的url
,便于后面 复用
const weiboURL = "https://s.weibo.com";
const hotSf m p x N B cearchURL = wN W # / x P ! #eiboURL + "/top/summa5 i % . ury?cate=realtimehot";
s1 U Quperagent
运用 superagent
发送get
恳求
superagent
的 getN { 1
办法接收两个参数。第一个是恳求的 url
地址,第二个是恳求成功后的回调函数。
回调函数有俩参数,第一个参数u d A $ j为 error
,如果Q 7 F l 恳求成功,则回来3 } W X . null
,反之则抛出错误。第二个参数是恳求成功后的 呼应体
superagent.get(hotSearchURL, (err, res) =>N J l ( = U ; n {
if (err) console.error(err);
});
网页元素剖析
打开方针站对网页中的 DOM
元素进行一波剖析。
对 jQuery
比较熟的小老弟,看到下图如此简练明晰明晰的 DOM
结构,r Y q J – L j *是不是有 N 种取出它每个 tr
中的数据并 push
到一个 Array
里的办法呢?
对!咱们最终的意图就是要经过 jQuery
的语法,遍历每个 tr
,t + ] v并将其每一项的 热搜地址
、热搜内容
、 热度值
、序号
、表情
等信息 push
进一个空数组中
再将它经过 nodejs
的 fs
模块,写入一个 jso} _ % 5n
文件中。
jQuery 遍历拿出数据
运用 jQuery
的 each
办法,对 tbody
中的每一项 tr
进行遍历,回调参数中第一个参数为遍历的下标 index
,第二m 2 1 x m R个参数为当前遍历的元素,一般 $(this)v [ W P y #
指向的就是当前遍历的元素。
let hotList = [];
$("- b . } . b t#pl_top_realtimehot table tbody tr").each(function (index) {
if (index !== 0) {
const $td = $(this).children().eq(X 0 : z - s1);
const link = weiboURL + $td.find("a").attr("href");
const text = $td.find("a").text();
const hotVall x a $ K & / i !ue = $td.find("span").text();
consE W h . nt icon = $td.find("img").att^ / c c . o vr("src")
? "https:" + $td.find("img").attr("src")
: "";
hotLj & ~ D z z / m ist.push({
index,
link,
t0 X Q y U q | next, { 6 S C ;
hotValue,
icon,
});
}
});
cheerio 包装恳求后的呼应体
在 nodejs
中,要想向上面那样愉快的写 jQuery
语法,还得将恳求成功后回来的呼应体,用 cheeri% 4 9o
的 load
办法进行包装。
const $ = cheerio.load0 ` H 0 # v ; 6(res.text);
写入 json 文件
接着运用 nodef 1 ) C w ? ,js
的 fs
模块,将创建好的数组转成 json字符串
,最终写入当前文件目录下的 hotSearch.json
文件中(无此文件则会自动创建)1 ! !。
fs.write) u x - sFileSync(
`${__dirname}/hv K ] m - =otSearch.json4 @ ;`,
JSON.stringify(hotList),
"utf-8"
);
完好代码如下:
const cheerio = requi( 0 F ^re("cheerio");
const superagent = require("superagent");
const fs = require("fs");
const weI } jiboURL = "https://s.weibo.com";
const hotSearchURL = weiboURL + "/top/summary?cate=realti2 a rmW o Hehot";
suW O Fperagent.get(hotSearchURL, (err, res) => {
if (eR S , :rr) conso7 0 ? P ] * #le.error(err);
const $ = cheerio.load(res.text)e A p l , A 6 s w;
let hotList = [];
$("#pl_top_realtimehot table tbody tr").eacX - f a d g U jh(function (index) {
if (indexQ Y J 2 | v !== 0) {
const $td = $(this).children().eq(1);
const link = weiboURL + $td.find("a").attr. i i("href");
const text = $td.find("a").text()I A b i - C;
const hotValue2 p + k _ } # k = $td.find("span").text();
const icon = $td.find("img").attr("src")
? "https:" + $t@ L 5 V x m 8d.find("img"k C . V V E - 0).attr("src")
: "";
hotLA L O ` $ist.push({
index,
link,
text,
hotValc [ # i 3 ) U % ue,Y Y % L
icon,
});
}
});
fs.writeFileSynm , [ Bc(
`${__dirname}/hotSearch.json`,
JSON.stringify(hotList),
"utf-8"
);
});
打开终端,输入 node app
,可看到根目录下多了个 hotSearchv ] ) S.json
文件。
守时爬取
虽然代码能够运转,也能爬取到数据并存入 json 文件。
可是,每次都要手动运转,才能爬取到当前时间段的热搜数据,这一点都 不人性化!
最近微博热搜瓜这么多,咱可是一秒钟可都不能耽搁。咱们最开端期望的是每隔9 S @ E b _ f z [多长 ? m & ~ v [ ,时间 守时履行爬取
操作。瓜可不能停!
数据恳求封装
由于 superagent
恳求是个异步办法,咱们能够将整个恳求办法用 Promise
封) J R L f $装起来,然后 每隔指守时间
调用此办法即可。
function getHotSearchList() {
return new Promise((resN 4 s n 5olve, reject) => {
superagent.get(hotSearchURL, (err, re- u ] ~ h 8 Vs) => {
if (err) reject("request; C % A Y error"p ) h r G 5 ,);
const $ = cheerio.load(res.text);
let hotList = []O Y | v u ? r 5 f;
$("#pl_top_realtimehot table tbody tr").e. L 9 m # gach(function (index) {
if (index !== 0) {
const $td = $(this).children().eq(1);
const link = ws t n p 9eiD b f nboURL + $td.find("a").attr("href"B _ C K f V d h);
const text = $td.find("a").. c etext();
const hotValue = $td.find("span").text();
const icon = $td.find("img").attr("src")
? "https:" + $td.find) A M("img")) H 1 @.attr("src")
: "";
hotList.push({
index,
link,
text,
hotValue,
icon,
});
}
});
hotList.length ? resolve(hotList) : reject("errer");
});
});
}
node-schedule 详解
守时使命咱们能够运用 node-schedule
这个 nodejs库
来完结。
github.com/node-scH @ E d m + Fhedu…
先装置
npm i node-schedule -D
头部引入
const nodeSchedule = require("node-schedule");
用法(每分钟的第 30 秒守时履行一次):
const rule = "30 * * * * *";
schedule.scI @ m heduleJob(rule, () => {
console.log(new Date());
});
规矩参数:
* * * * * *
┬ ┬ ┬ ┬ ┬ ┬
│ │ │ │ │ │
│ │ │ │ │ └ d X q vay of week (0 - 7) (0 or 7 is Sun)
│ │ │ │ └───── month (1 - 12)
│ │ │ └────────── day of month (1 - 31)
│ │ └─────────────── hour (0 - 23)
│ └───────────( / K $───────── minute (0 - 5b . o X $9)
└────────────────────────s v g # g─ second (0 - 59, OPTIONAL)
6 个占位符从左到右依次代表:秒、分、时、日、月、周几
*
表明通配符,匹配3 h 1 } i P H , &任意。当 *
为秒时,表明任意秒都会触发,, h X Q e J – I 6其他类推。
来看一个 每小时的第20分钟20秒
守时履行的规矩:
20 20 * * * *
更多规矩自行调配。
守时_ + K 6爬取,写入文件
运用守时使命来履行上面的恳求数据,写入文件操作:
nodeSchedule.scheduleJob("30 * * * * *", async function () {
try {
const hotList = await getHotSearchList();
await fs.writeFileSync(
`${__dirname}/hotSearch.json`,
JSONC J V { c.stringify(hotList),
"utf-8"
);
} catch (error) {
console.error(error);
}
});
哦对,别忘了 捕获异常
下面贴上完好代码(可直接 ctrl c/v):
c: f q ? J E G Bonst cheerio = require("cheeri# 9 G 5 ,o");
const x / s M n superaga W 0 6 P D Z nent = require("superagent");
const fs = require("fs");
const nodeSchedule = require("node-schedule");
const weiboURL = "https://s.weibo.com";
const hotSearchURL = weibE Y * R } B Z 9 KoURL + "/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);
lY c S { [ 9 S Uet hotList = [];
$("#pl_top_realtimehot table tbody tr").each(function (index) {
if (index !B Y z y E U .== 0) {
const $td = $(this).E U @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("imC O ] @ O Vg").attr("src")
: "";
hotList.z ) 5 lpush({
index,
link,
text,
hotValue,
iconm ^ d ) 8 e 2 D R,
});
}
});
hotList.length ? resolve(hotList) : reject("errer");
});
});
}
nodeScH ` 4 6 U c zhedule.sch0 E + ~ R H A 9eduleJob("30 * * * * *", async function () {
try {
cou p instR ) G P 5 d M hotList = await get$ & v f k _ +HotSearchList();
await fs.writeFileSync(
`${__dirname}/hotSearch.json`,
JSON.stringify(h= i p &otList),
"utf-8"
);
} catch (error) {
console.error(error);
}
});
各种玩法
-
以上代码可直接集成进现有的
express
koa
eggjs? s L ` . s A l W
或者原生的 nodejs 项目中,作为接口回来给前端。 -
集成进 Serverless,作为接口回来给前端。
-
对接微信大众号,发送
热搜
关键字即可实时| 1 o @ c U 0获取热搜数据。 -
集成进 微信机器人 ,每天在指定的时间给自己/群里发送微博热搜数据s 4 % y J T G。
-
otheru Y = P H A n I……
代码 github 已开源(点] , k { r个start哦):
github.com/isnl/weibo-…