您好,登錄后才能下訂單哦!
使用Nodejs怎么編寫(xiě)一個(gè)定時(shí)爬蟲(chóng)?針對(duì)這個(gè)問(wèn)題,這篇文章詳細(xì)介紹了相對(duì)應(yīng)的分析和解答,希望可以幫助更多想解決這個(gè)問(wèn)題的小伙伴找到更簡(jiǎn)單易行的方法。
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: '艦長(zhǎng)' } 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 }
很明顯這個(gè)爬蟲(chóng)只能手動(dòng)觸發(fā),直接跑還需要個(gè)命令行和node環(huán)境,于是就給他用Koa2開(kāi)了個(gè)頁(yè)面服務(wù),寫(xiě)一個(gè)極其簡(jiǎn)陋的頁(yè)面
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);
由于頁(yè)面沒(méi)有節(jié)流防抖,當(dāng)前版本又只能實(shí)時(shí)爬取,等待時(shí)間較長(zhǎng),頻繁刷新自然會(huì)觸發(fā)b站的反爬蟲(chóng)機(jī)制,于是當(dāng)前服務(wù)器ip就被風(fēng)控了。
于是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,此時(shí)timer為假,throttle觸發(fā)可以進(jìn)入計(jì)時(shí)器 }, delay) } }
再添加節(jié)流防抖的同時(shí),使用偽實(shí)時(shí)爬蟲(chóng)(通過(guò)定時(shí)任務(wù)一分鐘爬取一次)
這種情況我們需要去定時(shí)執(zhí)行爬蟲(chóng)腳本了,這個(gè)時(shí)候我就想到了就可以利用egg的schedule功能了,可是不想讓一個(gè)爬蟲(chóng)程序如此“大材小用”,遇事不決,百度一下。于是就有了下面的方案
Node Schedule是用于Node.js的靈活的cron類和非cron類作業(yè)調(diào)度程序。 它允許您使用可選的重復(fù)規(guī)則來(lái)計(jì)劃作業(yè)(任意函數(shù)),以在特定日期執(zhí)行。 它在任何給定時(shí)間僅使用一個(gè)計(jì)時(shí)器(而不是每秒鐘/分鐘重新評(píng)估即將到來(lái)的作業(yè))。
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 的第一個(gè)參數(shù)需要如下按照規(guī)則輸入
Node Schedule規(guī)則按下表表示
* * * * * *
┬ ┬ ┬ ┬ ┬ ┬
│ │ │ │ │ |
│ │ │ │ │ └ 星期幾,取值:0 - 7,其中 0 和 7 都表示是周日
│ │ │ │ └─── 月份,取值:1 - 12
│ │ │ └────── 日期,取值:1 - 31
│ │ └───────── 時(shí),取值:0 - 23
│ └──────────── 分,取值:0 - 59
└─────────────── 秒,取值:0 - 59(可選)
也可以指定一個(gè)具體的時(shí)間,如:const date = new Date()
看懂規(guī)則我們自己實(shí)現(xiàn)一個(gè)
const schedule = require('node-schedule'); // 定義一個(gè)時(shí)間 let date = new Date(2021, 3, 10, 12, 00, 0); // 定義一個(gè)任務(wù) let job = schedule.scheduleJob(date, () => { console.log("現(xiàn)在時(shí)間:",new Date()); });
上面的例子就代表到2021年3月10日12點(diǎn)的時(shí)候執(zhí)行報(bào)時(shí)
除了基礎(chǔ)的用法,我們還可以使用一些更為靈活的方法來(lái)實(shí)現(xiàn)定時(shí)任務(wù)。
3.1、隔一分鐘執(zhí)行一次
const schedule = require('node-schedule'); // 定義規(guī)則 let rule = new schedule.RecurrenceRule(); rule.second = 0 //每分鐘 0 秒執(zhí)行一次 // 啟動(dòng)任務(wù) let job = schedule.scheduleJob(rule, () => { console.log(new Date()); });
rule 支持設(shè)置的值有 second、minute、hour、date、dayOfWeek、month、year 等。
一些常見(jiàn)的規(guī)則如下表
每秒執(zhí)行
rule.second = [0,1,2,3......59];
每分鐘 0 秒執(zhí)行
rule.second = 0;
每小時(shí) 30 分執(zhí)行
rule.minute = 30;
rule.second = 0;
每天 0 點(diǎn)執(zhí)行
rule.hour =0;
rule.minute =0;
rule.second =0;
每月 1 號(hào)的 10 點(diǎn)執(zhí)行
rule.date = 1;
rule.hour = 10;
rule.minute = 0;
rule.second = 0;
每周一、周三、周五的 0 點(diǎn)和 12 點(diǎn)執(zhí)行
rule.dayOfWeek = [1,3,5];
rule.hour = [0,12];
rule.minute = 0;
rule.second = 0;
可以使用 cancel() 終止一個(gè)運(yùn)行中的任務(wù)。當(dāng)任務(wù)出現(xiàn)異常及時(shí)取消終止任務(wù)
job.cancel();
關(guān)于使用Nodejs怎么編寫(xiě)一個(gè)定時(shí)爬蟲(chóng)問(wèn)題的解答就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,如果你還有很多疑惑沒(méi)有解開(kāi),可以關(guān)注億速云行業(yè)資訊頻道了解更多相關(guān)知識(shí)。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。