今天我們要讓之前的程式能跟 Chat Bot 連動。
直接從程式中 POST 過去啊,難道還要透過 Worker?
對沒錯,不用,我們可以直接從程式中處理。
讓我們回顧一下我們的 checker
函式:
async function checker(courses) {
// 一樣,確認子頁面存在再操作
await page.waitForSelector("#stfseldListDo");
const child_page = await (await page.$("#stfseldListDo")).contentFrame();
// 用無窮迴圈重複執行,直到想停止時手動結束程式
while (true) {
// 遍歷每個課程,檢查是否有可加選的課程
for (let i = 0; i < courses.length; i++) {
// 在子頁面中注入程式確認課程人數狀態,後方是帶入的查詢參數
const data = await child_page.evaluate(injection.getInfo, courses[i].code, courses[i].class, courses[i].type, courses[i].form);
courses[i].seats = data.限修人數 - data.已分發人數;
}
// 印出所有可加選課程
console.log(
"---\n" +
courses
.filter((course) => course.seats > 0)
.map((course) => `${course.name} 還有 ${course.seats} 個空位`)
.join("\n")
);
// 冷卻時間,避免癱瘓系統
await child_page.waitForTimeout(30 * 1000);
}
}
我們這裡會一直印出有空位的課以及空多少位置。
但你總不希望一直被訊息騷擾吧?所以我們會在位置發生變動時再發送訊息。
我們需要先加上 node-fetch
Package:
npm i node-fetch@2
然後引入:
const fetch = require("node-fetch");
就是傳訊息的函式:
async function send(msg) {
// 發送訊息
await fetch(`https://api.telegram.org/bot${process.env.TOKEN}/sendMessage`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ chat_id: +process.env.CHAT_ID, parse_mode: "MarkdownV2", text: msg }),
});
}
這裡我們用環境變數來儲存 TOKEN 及 CHAT_ID。(當然你也可以一起放到 config 裡面)
至於 CHAT_ID 要怎麼取得?你就在 Bot 上寫個回傳 Chat_ID 的東西就好啦。
// Bot
if (text === "id") {
await fetch(`https://api.telegram.org/bot${TOKEN}/sendMessage`, {
method: "POST",
headers: { "Content-Type": "application/json" },
// 回覆 Chat ID
body: JSON.stringify({ chat_id, parse_mode: "MarkdownV2", text: chat_id.toString() }),
});
}
async function checker(courses) {
// 一樣,確認子頁面存在再操作
await page.waitForSelector("#stfseldListDo");
const child_page = await (await page.$("#stfseldListDo")).contentFrame();
// 這裡多了個儲存空位狀態的東西
const seats = {};
// 用無窮迴圈重複執行,直到想停止時手動結束程式
while (true) {
// 遍歷每個課程,檢查是否有可加選的課程
for (let i = 0; i < courses.length; i++) {
// 在子頁面中注入程式確認課程人數狀態,後方是帶入的查詢參數
const data = await child_page.evaluate(injection.getInfo, courses[i].code, courses[i].class, courses[i].type, courses[i].form);
courses[i].seats = data.限修人數 - data.已分發人數;
}
// 空位數有變化再放進來
const changed = {};
courses
.forEach((course) => {
if (seats[course.name] !== course.seats) {
// 空位數有變化
changed[course.name] = course.seats;
seats[course.name] = course.seats; // 更新空位數
}
});
// 如果有空位數有變化,傳送訊息
if (Object.keys(changed).length > 0) {
// 只發送有位置的訊息,可以發送 Markdown 格式的訊息
let msg = Object.entries(changed)
.map(([name, seats]) => (seats ? `${name} 目前有 **${seats}** 個空位` : ""))
.filter((x) => !!x)
.join("\n");
// 沒有 await 的必要,因為不影響
send(msg);
}
// 冷卻時間,避免癱瘓系統
await child_page.waitForTimeout(30 * 1000);
}
}
我們用一個 changed 來確認空位數是否有變化。
有變化的話,再傳訊息。
完成!
以 10/04 20:00 ~ 10/05 20:00 文章觀看數增加值排名
+230
JS 07 - 原型方法:欲達則必速
+155
Day 18:數據蒐集、資料視覺化、數據分析
+134
Day20 Android - Retrofit(Get)
+133
[Day30] 完結灑花❀ 看完賽心得順便用Python畫 3D 漸層花朵!
+133
【Day 20】Google Apps Script - API 篇回顧整理
+132
Day 1 無限手套 AWS 版:掌控一切的 5 + 1 雲端必學主題
+122
[面試][資料庫]如何解決高併發情境的商品秒殺問題
+120
[Day2] 抓取每日收盤價
+117
Day 23【Tokens' Owner】FUN SIDE PROJECT
+112
從零開始的8-bit迷宮探險【Level 27】神助攻-老弟幫我配個音效