Nodejs實現(xiàn)定時爬蟲的完整實例
事件起因
前兩天要幫朋友B站艦長群審核,一個個去艦長列表查找,自然不是一個程序猿的首選,把任務交給計算機讓他自己做,摸魚才是正道。理論成立開始Coding .
由于已知艦長列表的 API 爬蟲使用 Axios 直接訪問接口
于是花了億點點時間寫完了這段爬蟲我稱之為bilibili-live-captain-tools 1.0
const axios = require('axios')
const roomid = "146088"
const ruid = "642922"
const url = `https://api.live.bilibili.com/xlive/app-room/v2/guardTab/topList?roomid=${roomid}&ruid=${ruid}&page_size=30`
const Captin = {
1: '總督',
2: '提督',
3: '艦長'
}
const reqPromise = url => axios.get(url);
let CaptinList = []
let UserList = []
async function crawler(URL, pageNow) {
const res = await reqPromise(URL);
if (pageNow == 1) {
CaptinList = CaptinList.concat(res.data.data.top3);
}
CaptinList = CaptinList.concat(res.data.data.list);
}
function getMaxPage(res) {
const Info = res.data.data.info
const { page: maxPage } = Info
return maxPage
}
function getUserList(res) {
for (let item of res) {
const userInfo = item
const { uid, username, guard_level } = userInfo
UserList.push({ uid, username, Captin: Captin[guard_level] })
}
}
async function main(UID) {
const maxPage = await reqPromise(`${url}&page=1`).then(getMaxPage)
for (let pageNow = 1; pageNow < maxPage + 1; pageNow++) {
const URL = `${url}&page=${pageNow}`;
await crawler(URL, pageNow);
}
getUserList(CaptinList)
console.log(search(UID, UserList))
return search(UID, UserList)
}
function search(uid, UserList) {
for (let i = 0; i < UserList.length; i++) {
if (UserList[i].uid === uid) {
return UserList[i];
}
}
return 0
}
module.exports = {
main
}
很明顯這個爬蟲只能手動觸發(fā),直接跑還需要個命令行和node環(huán)境,于是就給他用Koa2開了個頁面服務,寫一個極其簡陋的頁面
const Koa = require('koa');
const app = new Koa();
const path = require('path')
const fs = require('fs');
const router = require('koa-router')();
const index = require('./index')
const views = require('koa-views')
app.use(views(path.join(__dirname, './'), {
extension: 'ejs'
}))
app.use(router.routes());
router.get('/', async ctx => {
ctx.response.type = 'html';
ctx.response.body = fs.createReadStream('./index.html');
})
router.get('/api/captin', async (ctx) => {
const UID = ctx.request.query.uid
console.log(UID)
const Info = await index.main(parseInt(UID))
await ctx.render('index', {
Info,
})
});
app.listen(3000);
由于頁面沒有節(jié)流防抖,當前版本又只能實時爬取,等待時間較長,頻繁刷新自然會觸發(fā)b站的反爬蟲機制,于是當前服務器ip就被風控了。
于是bilibili-live-captain-tools 2.0橫空出世
function throttle(fn, delay) {
var timer;
return function () {
var _this = this;
var args = arguments;
if (timer) {
return;
}
timer = setTimeout(function () {
fn.apply(_this, args);
timer = null; // 在delay后執(zhí)行完fn之后清空timer,此時timer為假,throttle觸發(fā)可以進入計時器
}, delay)
}
}
再添加節(jié)流防抖的同時,使用偽實時爬蟲(通過定時任務一分鐘爬取一次)
這種情況我們需要去定時執(zhí)行爬蟲腳本了,這個時候我就想到了就可以利用egg的schedule功能了,可是不想讓一個爬蟲程序如此“大材小用”,遇事不決,百度一下。于是就有了下面的方案
使用 Node Schedule 實現(xiàn)定時任務
Node Schedule是用于Node.js的靈活的cron類和非cron類作業(yè)調度程序。 它允許您使用可選的重復規(guī)則來計劃作業(yè)(任意函數(shù)),以在特定日期執(zhí)行。 它在任何給定時間僅使用一個計時器(而不是每秒鐘/分鐘重新評估即將到來的作業(yè))。
一、安裝 node-schedule
npm install node-schedule # 或 yarn add node-schedule
二、基本用法
一起啊看一下官方給的例子
const schedule = require('node-schedule');
const job = schedule.scheduleJob('42 * * * *', function(){
console.log('The answer to life, the universe, and everything!');
});
schedule.scheduleJob 的第一個參數(shù)需要如下按照規(guī)則輸入
Node Schedule規(guī)則按下表表示
* * * * * *
┬ ┬ ┬ ┬ ┬ ┬
│ │ │ │ │ |
│ │ │ │ │ └ 星期幾,取值:0 - 7,其中 0 和 7 都表示是周日
│ │ │ │ └─── 月份,取值:1 - 12
│ │ │ └────── 日期,取值:1 - 31
│ │ └───────── 時,取值:0 - 23
│ └──────────── 分,取值:0 - 59
└─────────────── 秒,取值:0 - 59(可選)
也可以指定一個具體的時間,如:const date = new Date()
看懂規(guī)則我們自己實現(xiàn)一個
const schedule = require('node-schedule');
// 定義一個時間
let date = new Date(2021, 3, 10, 12, 00, 0);
// 定義一個任務
let job = schedule.scheduleJob(date, () => {
console.log("現(xiàn)在時間:",new Date());
});
上面的例子就代表到2021年3月10日12點的時候執(zhí)行報時
三、高級用法
除了基礎的用法,我們還可以使用一些更為靈活的方法來實現(xiàn)定時任務。
3.1、隔一分鐘執(zhí)行一次
const schedule = require('node-schedule');
// 定義規(guī)則
let rule = new schedule.RecurrenceRule();
rule.second = 0
//每分鐘 0 秒執(zhí)行一次
// 啟動任務
let job = schedule.scheduleJob(rule, () => {
console.log(new Date());
});
rule 支持設置的值有 second、minute、hour、date、dayOfWeek、month、year 等。
一些常見的規(guī)則如下表
每秒執(zhí)行
rule.second = [0,1,2,3......59];
每分鐘 0 秒執(zhí)行
rule.second = 0;
每小時 30 分執(zhí)行
rule.minute = 30;
rule.second = 0;
每天 0 點執(zhí)行
rule.hour =0;
rule.minute =0;
rule.second =0;
每月 1 號的 10 點執(zhí)行
rule.date = 1;
rule.hour = 10;
rule.minute = 0;
rule.second = 0;
每周一、周三、周五的 0 點和 12 點執(zhí)行
rule.dayOfWeek = [1,3,5];
rule.hour = [0,12];
rule.minute = 0;
rule.second = 0;
四、終止任務
可以使用 cancel() 終止一個運行中的任務。當任務出現(xiàn)異常及時取消終止任務
job.cancel();
總結
node-schedule 是 Node.js 的一個 定時任務(crontab)模塊。我們可以使用定時任務來對服務器系統(tǒng)進行維護,讓其在固定的時間段執(zhí)行某些必要的操作,還可以使用定時任務發(fā)送郵件、爬取數(shù)據(jù)等;
到此這篇關于Nodejs實現(xiàn)定時爬蟲的文章就介紹到這了,更多相關Nodejs定時爬蟲內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Node.js處理I/O數(shù)據(jù)之使用Buffer模塊緩沖數(shù)據(jù)
這篇文章介紹了Node.js使用Buffer模塊緩沖數(shù)據(jù)的方法,文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-07-07
從零開始學習Node.js系列教程三:圖片上傳和顯示方法示例
這篇文章主要介紹了Node.js圖片上傳和顯示方法,結合實例形式分析了nodejs基于http傳輸圖片文件及顯示圖片的相關實現(xiàn)步驟與操作技巧,需要的朋友可以參考下2017-04-04

