1. 程式人生 > 程式設計 >Nodejs實現定時爬蟲的完整例項

Nodejs實現定時爬蟲的完整例項

事件起因

前兩天要幫朋友B站艦長群稽核,一個個去艦長列表查詢,自然不是一個程式猿的首選,把任務交給計算機讓他自己做,摸魚才是正道。理論成立開始Coding .

由於已知艦長列表的 API 爬蟲使用 Axios 直接訪問介面

於是花了億點點時間寫完了這段爬蟲我稱之為bilibili-live-captain-tools 1.0

const axios = require('axios')
const roomid = "146088"
const ruid = "642922"
const url = `FkdpKekGhttps://api.live.bilibili.com/www.cppcns.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,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 }

很明顯這個爬蟲只能手動觸發,直接跑還需要個命令列和node環境,於是就給他用Koa2開了個頁面服務,寫一個極其簡陋的頁面

const Koa = require('koa'FkdpKekG);
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: 'e
js
' })) 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);

由於頁面沒有節流防抖,當前版本又只能實時爬取,等待時間較長,頻繁重新整理自然會觸發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後執行完fn之後清空timer,此時timer為假,throttle觸發可以進入計時器
 },delay)
 }
}

再新增節流防抖的同時,使用偽實時爬蟲(通過定時任務一分鐘爬取一次)

這種情況我們需要去定時執行爬蟲指令碼了,這個時候我就想到了就可以利用egg的schedule功能了,可是不想讓一個爬蟲程式如此“大材小用”,遇事不決,百度一下。於是就有了下面的方案

使用 Node Schedule 實現定時任務

Node Schedule是用於Node.js的靈活的cron類和非cron類作業排程程式。 它允許您使用可選的重複規則來計劃作業(任意函式),以在特定日期執行。 它在任何給定時間僅使用一個計時器(而不是每秒鐘/分鐘重新評估即將到來的作業)。

一、安裝 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 的第一個引數需要如下按照規則輸入

Node Schedule規則按下表表示

* *&FkdpKekGnbsp; * * * *
┬ ┬ ┬ ┬ ┬ ┬
│ │ │ │ │ |
│ │ │ │ │ └ 星期幾,取值:0 - 7,其中 0 和 7 都表示是週日
│ │ │ │ └─── 月份,取值:1 - 12
│ │ │ └────── 日期,取值:1 - 31
│ │ └───────── 時,取值:0 - 23
│ └──────────── 分,取值:0 - 59
└─────────────── 秒,取值:0 - 59(可選)
也可以指定一個具體的時間,如:const date = new Date()

看懂規則我們自己實現一個

const schedule = require('node-schedule');

// 定義一個時間
let date = new Date(2021,3,10,12,00,0);

// 定義一個任務
let job = schedule.scheduleJob(date,() => {
 console.log("現在時間:",new Date());
});

上面的例子就代表到2021年3月10日12點的時候執行報時

三、高階用法

除了基礎的用法,我們還可以使用一些更為靈活的方法來實現定時任務。

3.1、隔一分鐘執行一次

const schedule = require('node-schedule');

// 定義規則
let rule = new schedule.RecurrenceRule();
rule.second = 0
//每分鐘 0 秒執行一次

// 啟動任務
let job = schedule.scheduleJob(rule,() => {
 console.log(new Date());
});

rule 支援設定的值有 second、minute、hour、date、dayOfWeek、month、year 等。

一些常見的規則如下表

每秒執行
rule.second = [0,1,2,3......59];
每分鐘 0 秒執行
rule.second = 0;
每小時 30 分執行
rule.minute = 30;
rule.second = 0;
每天 0 點執行
rule.hour =0;
rule.minute =0;
rule.second =0;
每月 1 號的 10 點執行
rule.date = 1;
rule.hour = 10;
rule.minute = 0;
rule.second = 0;
每週一、週三、週五的 0 點和 12 點執行
rule.dayOfWeek = [1,5];
rule.hour = [0,12];
rule.minute = 0;
rule.second = 0;

四、終止任務

可以使用 cancel() 終止一個執行中的任務。當任務出現異常及時取消終止任務

job.cancel();

總結

node-schedule 是 Node.js 的一個 定時任務(crontab)模組。我們可以使用定時任務來對伺服器系統進行維護,讓其在固定的時間段執行某些必要的操作,還可以使用定時任務傳送郵件、爬取資料等;

到此這篇關於Nodejs實現定時爬蟲的文章就介紹到這了,更多相關Nodejs定時爬蟲內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!