前一篇我們對於 Crontab 已經有一個基本的概念,接下來當然要套用到實際案例上,不然認識了也沒用,所以這一篇我們就來簡單實作一個 Crontab + Node.js 的範例。
首先我們先來建立一個專案,前面這個指令應該是苦瓜爛熟了,所以我就不多說了:
mkdir crontab-example-nodejs
cd crontab-example-nodejs
npm init -y
touch index.js
接下來我們還要額外安裝一個套件,也就是 cron
。
npm i cron
Cron 的使用方式非常的簡單,依照官方範例文件所提供的程式碼來看,只要先引入 cron
套件,接著就可以使用 CronJob
這個類別來建立一個 CronJob。
var CronJob = require('cron').CronJob;
var job = new CronJob(
'* * * * * *',
function() {
console.log('You will see this message every second');
},
null,
true,
'America/Los_Angeles'
);
稍微有一點複雜吧?那我們就來一個一個解釋:
但實際上來講,我們比較常這樣寫
const CronJob = require('cron').CronJob;
const job = new CronJob(
'* * * * * *',
function() {
console.log('You will see this message every second');
}
);
因為三~五個參數都是選填的,所以我們可以不用寫,而第一個參數就是我們要設定的時間,第二個參數就是我們要執行的程式碼,接著最後再補上一個 job.start()
就可以了。
const CronJob = require('cron').CronJob;
const job = new CronJob(
'* * * * * *',
function() {
console.log('You will see this message every second');
}
);
job.start();
Note
由於前一篇已經有提到 Crontab 的格式,所以這邊就不再贅述,如果你還不清楚的話,可以回去看一下前一篇。
反之,如果你期望停止這個排程的話,那就可以使用 job.stop()
來停止。
那麼你還記得我們在前面寫了兩隻爬蟲嗎?分別是:
透過 cron 的排程,我們就可以定時的去爬取資料,這樣就不用每次都要手動去執行了,而且也不用擔心忘記執行,所以我們就來實作一下吧!
首先我們先回顧一下前面寫的程式碼也就是 index.js
:
// index.js
const fs = require('fs');
const cheerio = require('cheerio');
const getData = async (url) => {
try {
const response = await fetch(url);
const data = await response.text();
return data;
} catch (error) {
console.log(error);
}
}
const crawler = async () => {
const html = await getData('https://ithelp.ithome.com.tw/2022ironman/signup/list');
const $ = cheerio.load(html); // 載入 html
const paginationInner = $('span.pagination-inner > a').last(); // 取得最後一頁的頁碼
const lastPage = Number(paginationInner.text()); // 取得最後一頁的頁碼文字並轉成數字
const data = [];
// 用 for 迴圈來爬取每一頁的資料
for(let i = 1; i <= lastPage; i++) {
console.log(`正在爬取第 ${i} 頁`);
const html = await getData(`https://ithelp.ithome.com.tw/2022ironman/signup/list?page=${i}`);
const $ = cheerio.load(html); // 載入 html
const listCard = $('.list-card');
listCard.each((index, element) => {
const name = $(element).find('.contestants-list__name').text();
const category = $(element).find('.tag span').text();
const title = $(element).find('.contestants-list__title').text();
const url = $(element).find('.contestants-list__title').attr('href');
data.push({
name,
category,
title,
url,
});
});
// 避免過度請求增加伺服器負擔
await new Promise((resolve) => {
setTimeout(() => {
resolve();
}, 5000); // 5 秒跑一次
})
}
fs.writeFileSync('./data.json', JSON.stringify(data));
}
crawler();
前面這一個程式碼就是用來爬取鐵人賽參賽者列表的,而我們要做的就是把這個程式碼改成可以定時執行的,,但其實用法很簡單,只要把程式碼包在 CronJob
裡面就可以了
// index.js
const fs = require('fs');
const CronJob = require('cron').CronJob;
const cheerio = require('cheerio');
const getData = async (url) => {
// ... 略過程式碼
}
const crawler = async () => {
// ... 略過程式碼
}
const job = new CronJob(
'* * * * * *',
function() {
crawler();
}
);
這樣子我們就可以達到每分鐘爬取一次的效果,但實際上來講,我們並不需要那麼頻繁的撈取資料,所以我們可以改成每個禮拜一早上九點爬取一次
// index.js
// ... 略過程式碼
const job = new CronJob(
'0 9 * * 1',
function() {
crawler();
}
);
job.start();
那麼另一個爬取鐵人賽文章詳細資訊的程式碼也是一樣的,只是這邊就留給你自己試試看了,我就不多做說明與解釋囉~
現在應該會發生一點混亂點,也就是 Node.js 的 Cron 跟 Linux 的 Cron 有什麼差別呢?
首先我們在 npm 所下載安裝的 cron
套件,主要是運行於 Node.js 環境下的,而 Linux 則是一個作業系統,所以這兩個東西是不太一樣的東西,只是概念以及時間格式是類似相同的,所以有時候會讓人有點混淆。
因此通常你會比較常看到人家講 node-cron
,但只是因為你在安裝 npm 套件時,指令是這樣...
npm i cron
所以才會有一點混亂,但其實這兩個東西是不一樣的,只是概念上有點類似而已。
那這兩者有什麼明顯差異嗎?剛才有提到概念以及時間的格式非常雷同,但是大多在 Linux 上的 Cron 比較常用來執行 Shell Script,所以與 Node.js 的 Cron 相比會比較難以擴充成更複雜的邏輯。
Note
Shell Script 是一個純文字檔案,裡面可以寫一些指令,例如ls
、cd
、mkdir
等等,而這些指令都是可以在終端機上執行的,所以你可以把 Shell Script 想像成一個可以在終端機上執行的檔案。
簡而總之,如果你想要在 Node.js 上執行自己所撰寫的 JavaScript 程式碼,那就使用 node-cron
,如果你想要在 Linux 上執行 Shell Script,那就使用 Linux 的 Cron。
那麼這一篇也差不多了,我們就先到這邊結束,我們下一篇見囉~