#17 Automation (5)

今天处里剩下的部分:checker 函式和它注入页面的辅助函式。

checker

checker 函式基本上就是帮我们重复地跑无穷回圈,每隔一段时间就去刷一下资料,然後如果有可加选的空位则提醒使用者。
在这里提醒就是印到 console 上,但之後我们应该会让它可以用通讯软件通知。

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);
    }
}

因为学校系统可能有点年纪了,所以我们每刷完一次就冷却 30 秒。

injection.getInfo

这个函式的用途是在页面中建立一个查询的 iframe,并解析 iframe 中资料後回传至主要程序。

async function getInfo(code, group, type, form) {
    // 制造一个新的 iframe,就跟选课系统一样
    const f = document.createElement("iframe");
    f.src = `https://cos1s.ntnu.edu.tw/AasEnrollStudent/CourseQueryCtrl?year=110&term=1&courseCode=${code}&courseGroup=${group}&deptCode=${type}&formS=${form}&classes1=&deptGroup=&action=showInfo`;
    document.body.appendChild(f);
    // 等待页面载入完成,为了预防卡死 5 秒强制结束
    await new Promise((resolve) => {
        f.onload = resolve;
        setTimeout(resolve, 5000);
    });
    await new Promise((resolve) => setTimeout(resolve, 1000));
    // 用 try 来预防莫名其妙的错误
    try {
        // 取得 iframe 内的资料
        const raw = f.contentDocument.querySelector("#fieldcontainer-1010-targetEl").innerText;
        // 删除 iframe,预防最後开太多 iframe 记忆体用量太大
        f.remove();
        // 将资料从文字中拆解出来
        // 组成一一对应,例如限修人数: 10, 已分发人数: 10
        const info = raw
            .replace(/[\s\n]+/g, "")
            .match(/\D+?:\d+/g)
            .map((x) => x.split(":"))
            .reduce((a, c) => {
                try {
                    a[c[0]] = +c[1];
                } catch {}
                return a;
            }, {});
        return info;
    } catch {
        return {};
    }
}

这样,我们的程序就写好了。
可以试试在 dev = true 的状态跟 dev = false 的状态有什麽差别。
在验证码辨识时可能会需要一点时间,可能会长至 30 秒。

下个章节

接下来,我们就要来让这个程序串接 Chat Bot 了。


每日铁人赛热门 Top 10 (0930)

以 9/30 20:00 ~ 10/01 20:00 文章观看数增加值排名

  1. +199 Day 1 无限手套 AWS 版:掌控一切的 5 + 1 云端必学主题
    • 作者: 用图片高效学程序
    • 系列:无限手套 AWS 版:掌控一切的 5 + 1 云端必学主题
  2. +184 Proxmox VE 安装容器:Rocky Linux 8.4 及其它应用 (WordPress, Nextcloud, Odoo)
    • 作者: Jason Cheng (节省哥)
    • 系列:突破困境:企业开源虚拟化管理平台
  3. +156 Day 2 AWS 是什麽?又为何企业这麽需要 AWS 人才?
    • 作者: 用图片高效学程序
    • 系列:无限手套 AWS 版:掌控一切的 5 + 1 云端必学主题
  4. +155 Android学习笔记22
    • 作者: blossomgp3
    • 系列:Android kotlin &MVVM
  5. +154 [Day28] 戏弄老板! 教你用Machine Learning将老板玩弄於股掌之间!
    • 作者: lulu_meat
    • 系列:奇怪的知识增加了!原来程序还可以这样用?!
  6. +147 Day 3 云端四大平台比较:AWS . GCP . Azure . Alibaba
    • 作者: 用图片高效学程序
    • 系列:无限手套 AWS 版:掌控一切的 5 + 1 云端必学主题
  7. +140 Day 4 网路宝石:AWS VPC Region/AZ vs VPC/Subnet 关系介绍
    • 作者: 用图片高效学程序
    • 系列:无限手套 AWS 版:掌控一切的 5 + 1 云端必学主题
  8. +134 Day 5 网路宝石:AWS VPC 架构 Routes & Security (上)
    • 作者: 用图片高效学程序
    • 系列:无限手套 AWS 版:掌控一切的 5 + 1 云端必学主题
  9. +132 DAY19 - 在win10家用版上安装Docker Desktop
    • 作者: rs6000
    • 系列:总是学不来的中年大叔,孤独的自学之旅
  10. +125 从零开始的8-bit迷宫探险【Level 23】长老,这个水晶值多少钱?
    • 作者: 雪花冰
    • 系列:从零开始的8-bit迷宫探险!Swift SpriteKit 游戏开发实战

越来越多人完赛了!恭喜!
现在 Top 10 中的类型又变多了耶!


<<:  [Day 26] review 一下我们的程序,谈谈 DSL 和 DAO 的差异

>>:  Flask API-取得request资料(以ticks API为例)

参赛前言 & 系列文规划

大家好,我是 Ian,因为一些原因,我在年初的时候接触到嵌入式系统开发与系统软件实作。在这一年来也...

Day14 开发套件 - 范例程序码介绍03 iOS 端

最後来看Native 端(iOS): 补充:iOS 中的 .h 和.m 档 .h 为标头档,做为宣告...

Day6-控制器是在控什麽 controller说明

pod的管理与控制 对k8s来说,pod是k8s最小的元件,但是当我们在使用时,通常不会直接对pod...

Day15 AR装置的编年史(上) 最早的AR其实在半个世纪前就有个雏型了!?

1968年 在1968年,犹他大学的Ivan Sutherland和他的学生Bob Sproull创...

[13th-铁人赛]Day 9:Modern CSS 超详细新手攻略 - Specificity

今天要讲的主题是权重,权重在CSS中扮演着裁决者的角色,在被重复赋予样式时,决定最终该显示哪一个样式...