網頁系統 · Selected Work · 2026

作業預警系統

台大 NTUCOOL(Canvas LMS)常常把作業、考試截止日淹沒在一堆課程頁面裡。 這個工具自動抓取所有課程的作業與考試截止日期,用 launchd 排程 每小時檢查一次,快到期時透過 Telegram Bot 主動發送通知到手機上

Web 系統 / 自動化 個人專案 · 本機常駐 2026
NTUCOOL 作業截止通知網站畫面:頂部顯示上次更新時間與「重新整理」「發送 Telegram 通知」按鈕,下方是抓取進度清單(檢查登入憑證、連接 Canvas 官方 API、抓取作業/考試資料、掃描公告關鍵字、整理資料,全部已完成)與 Canvas 連線正常狀態,右側是本月迷你月曆並標示到期日,最下方是作業列表,列出 HW1(電腦視覺 Computer Vision)的截止時間與剩餘天數。

要解決的問題

台大 NTUCOOL 上每門課的作業、考試截止日都散落在各自的課程頁面, 沒有一個地方能一次看完所有作業的期限。更麻煩的是 NTUCOOL 這個 Canvas 站台不支援學生自行產生個人 API Token(設定頁沒有「已核准的整合」區塊), 一般常見的「拿 token 打 API」做法在這裡直接行不通。

認證方式:讀本機 Chrome 的登入 session

既然沒有 token,這個工具改用讀取本機 Chrome 目前登入 NTUCOOL 的 session cookie (靠 browser_cookie3 套件),不存密碼、不用手動複製貼上,也不必自動化登入流程去冒存密碼的風險。 代價是整個系統只能在使用者本機執行——雲端服務碰不到本機瀏覽器的資料, 所以這是刻意選擇的架構限制,不是技術債。中間也比較過爬蟲、Token、手動複製 cookie、 Bookmarklet、純前端讀 cookie 等將近十種方案,最後認證方式的取捨過程完整寫進專案的 README,作為之後回頭檢視決策的紀錄。

PythonFlaskReact (Vite) browser_cookie3Telegram Bot APIlaunchd

系統架構

NTUCOOL Canvas LMS Chrome session cookie main.py 抓取作業 / 考試 / 公告 New Quizzes 判斷 Flask API /api/refresh /api/notify /api/progress Telegram Bot 主動推播提醒 React 面板 即時進度 + 月曆 launchd 排程 StartInterval = 3600 curl -X POST /api/notify
NTUCOOL → main.py(Chrome session cookie)→ Flask API → Telegram Bot / React 面板;launchd 每小時排程呼叫 /api/notify

自動抓取 API

main.py 用已認證的 session 打 Canvas 的作業 API,抓出所有課程即將到期的作業; 考試的部分比較特別——NTUCOOL 的舊版 /quizzes API 會回 404,所以改成從作業 API 回傳的 is_quiz_assignment 欄位反推出 New Quizzes,再搭配 Calendar Events 與公告關鍵字掃描(低信度,只做提示、不觸發正式提醒) 補齊考試資訊。

排程:launchd 每小時檢查

本機常駐兩個 launchd 服務:一個是 RunAtLoad + KeepAlive 跑 Flask 常駐服務,另一個是 StartInterval=3600 每小時打一次 curl -X POST /api/notify。 故意讓排程打 API 而不是直接重跑一份 CLI 邏輯,這樣 CLI、排程、網頁按鈕三條觸發路徑 永遠共用同一套抓取與判斷邏輯,不會出現「網頁上看到的」跟「排程實際送出的」兜不起來的情況。 提醒本身是門檻式的(截止前 7 / 3 / 1 天各推播一次),用 state.json 記錄哪些提醒已經發過,避免同一個門檻重複轟炸。

Telegram Bot 通知

提醒最終都是透過自架的 Telegram Bot 傳送給使用者,讓使用者可以在手機收到通知。 分成兩種模式:
1. 排程觸發的門檻式提醒,系統定時檢查時發現有作業快到期限時會自動發送通知。
2. 按下網頁面按鈕觸發通知,一次查看當前所有未完成的作業。

網頁面板

除了背景排程,還做了一個 React + Flask 的輕量面板:手動觸發抓取、 即時輪詢顯示抓取進度(哪一步在跑、哪一步完成),作業/考試表格整列可點擊 直接跳轉回 NTUCOOL 對應頁面,右側搭配一個標示到期日的迷你月曆。 前後端共用同一套 progress_start / progress_step / progress_done 進度追蹤器,不管是排程還是手動按鈕觸發抓取,網頁上看到的都是同一份即時狀態。

每小時
launchd 排程檢查一次截止日期
7 / 3 / 1
天門檻式 Telegram 提醒,state.json 防重複
1 套邏輯
CLI、排程、網頁按鈕共用同一套抓取與通知函式

學到的事:有時候最合理的架構不是「把什麼都搬上雲端」,而是面對限制且尋找替代方案 NTUCOOL無法提供API Token,就沒有一個雲端服務能安全、穩定地做到這件事。 我轉而把系統設計成本機常駐、用launchd排程,一樣能做到全自動抓取資料,且不需要儲存帳號密碼,好用又安全。