前言 前一篇我們對於 Crontab 已經有一個基本的概念,接下來當然要套用到實際案例上,不然認識了也沒用,所以這一篇我們就來簡單實作一個 Crontab + Node.js 的範例。
專案環境 首先我們先來建立一個專案,前面這個指令應該是苦瓜爛熟了,所以我就不多說了:
1 2 3 4 mkdir crontab-example-nodejscd crontab-example-nodejsnpm init -y touch index.js
接下來我們還要額外安裝一個套件,也就是 cron
。
CronJob Cron 的使用方式非常的簡單,依照官方範例文件所提供的程式碼來看,只要先引入 cron
套件,接著就可以使用 CronJob
這個類別來建立一個 CronJob。
1 2 3 4 5 6 7 8 9 10 11 var CronJob = require ('cron' ).CronJob ;var job = new CronJob ( '* * * * * *' , function ( ) { console .log ('You will see this message every second' ); }, null , true , 'America/Los_Angeles' );
稍微有一點複雜吧?那我們就來一個一個解釋:
第一個參數:這個參數就是剛剛我們所提到的 Crontab 格式,也就是說,這個參數就是用來設定你要執行的時間。
第二個參數:這個參數就是你要執行的程式碼。
第三個參數:完成排程後要執行的程式碼。
第四個參數:是否立即執行。
第五個參數:時區。
但實際上來講,我們比較常這樣寫
1 2 3 4 5 6 7 8 const CronJob = require ('cron' ).CronJob ;const job = new CronJob ( '* * * * * *' , function ( ) { console .log ('You will see this message every second' ); } );
因為三~五個參數都是選填的,所以我們可以不用寫,而第一個參數就是我們要設定的時間,第二個參數就是我們要執行的程式碼,接著最後再補上一個 job.start()
就可以了。
1 2 3 4 5 6 7 8 9 10 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
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 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); const paginationInner = $('span.pagination-inner > a' ).last (); const lastPage = Number (paginationInner.text ()); const data = []; 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); 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 ); }) } fs.writeFileSync ('./data.json' , JSON .stringify (data)); } crawler ();
前面這一個程式碼就是用來爬取鐵人賽參賽者列表的,而我們要做的就是把這個程式碼改成可以定時執行的,但其實用法很簡單,只要把程式碼包在 CronJob
裡面就可以了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 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 (); } );
這樣子我們就可以達到每分鐘爬取一次的效果,但實際上來講,我們並不需要那麼頻繁的撈取資料,所以我們可以改成每個禮拜一早上九點爬取一次
1 2 3 4 5 6 7 8 9 10 11 12 const job = new CronJob ( '0 9 * * 1' , function ( ) { crawler (); } ); job.start ();
那麼另一個爬取鐵人賽文章詳細資訊的程式碼也是一樣的,只是這邊就留給你自己試試看了,我就不多做說明與解釋囉~
混亂知識點 現在應該會發生一點混亂點,也就是 Node.js 的 Cron 跟 Linux 的 Cron 有什麼差別呢?
首先我們在 npm 所下載安裝的 cron
套件,主要是運行於 Node.js 環境下的,而 Linux 則是一個作業系統,所以這兩個東西是不太一樣的東西,只是概念以及時間格式是類似相同的,所以有時候會讓人有點混淆。
因此通常你會比較常看到人家講 node-cron
,但只是因為你在安裝 npm 套件時,指令是這樣…
所以才會有一點混亂,但其實這兩個東西是不一樣的,只是概念上有點類似而已。
那這兩者有什麼明顯差異嗎?剛才有提到概念以及時間的格式非常雷同,但是大多在 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。
那麼這一篇也差不多了,我們就先到這邊結束,我們下一篇見囉~