今天写第二步「进入选课页面」、第三步「至加选页面」及第四步「查询你想要的课程」。
这个函式涵盖了第二步及第三步,因为不想分太多函式。
async function enter() {
// 进入选课系统
if (page.url().includes("IndexCtrl")) {
await page.click("#button-1017");
await page.waitForNavigation({ timeout: 10000 });
if (!page.url().includes("EnrollCtrl")) throw new Error("Enter Failed");
}
// 等待选课子页面出现
await page.waitForSelector("#stfseldListDo");
// 设定自动登出时间为 6 小时
await page.evaluate(() => {
window.countSecond = 6 * 60 * 60;
});
// 取得选课子页面,点击加选按钮进入加选画面
const child_page = await (await page.$("#stfseldListDo")).contentFrame();
await child_page.waitForSelector("#add");
await child_page.click("#add");
await child_page.waitForTimeout(500);
console.log("Entered System");
}
与登入时一样,我们用网址来判定状态并决定是否要执行。
在这里有个特别的地方:window.countSecond = 6 * 60 * 60
为什麽要这样?因为系统会自动登出,但因为太相信使用者,所以不知道为什麽这个机制做在前端而非後端用让 session 失效的方法。
接下来,因为网站是用 iframe 作系统分页的东西,所以必须用 .contentFrame()
取得 iframe 中的东西。
这也是为什麽不该用浏览器的重新整理的原因
那个 #add
就是进入加选页面最後一步的按钮啦!
query
会先用系统找到课程的资料,对於下一步的操作至关重要。
async function query() {
// 取得子页面
await page.waitForSelector("#stfseldListDo");
const child_page = await (await page.$("#stfseldListDo")).contentFrame();
const result = [];
// 等待所有操作的元素都出现
await Promise.all([child_page.waitForSelector("#serialNo-inputEl"), child_page.waitForSelector("#button-1059")]);
// 遍历所有设定里写的课程代码
for (const course of config.courses) {
debug(`Searching ${course}`);
// 输入代码,记得先清空,要不然第二个会叠上去
await child_page.$eval("#serialNo-inputEl", (elm) => (elm.value = ""));
await child_page.type("#serialNo-inputEl", course.toString().padStart(4, "0"));
await child_page.waitForTimeout(300);
// 案查询按钮
await child_page.click("#button-1059");
// 等待结果
await child_page.waitForSelector("#gridview-1113-body > tr");
await child_page.waitForTimeout(300);
// 从列表中拿资料,因为 id 唯一,所以应该只会有一项资料
const table = await child_page.$("#gridview-1113-body");
const data = await table.evaluate((table) => {
const data = [...table.children[0].children].map((elm) => elm.innerText);
table.innerHTML = "";
return data;
});
// 整理资料,毕竟拿到的会是一个阵列
result.push({
num: data[4].trim(),
name: data[5].trim(),
instructor: data[7].trim(),
time: data[8].trim(),
code: data[11].trim(),
class: data[19].trim(),
});
}
debug("Courses: ", result);
return result;
}
其实就是完全拟人的步骤,毕竟是自动化嘛!
明天应该会比较东西啦!
应该吧?
以 9/29 20:00 ~ 9/30 20:00 文章观看数增加值排名
+284
让程序码化为 API Doc
+273
终章 - 资安碎碎念与心得
+224
[Day 28] 资料产品开发实务 - 非机器学习模型
+205
Day 1 无限手套 AWS 版:掌控一切的 5 + 1 云端必学主题
+197
[Day30] 完结洒花❀ 看完赛心得顺便用Python画 3D 渐层花朵!
+179
[重构倒数第30天] - 使用 Vue3 Composition API 重构 JS 选单
+178
[DAY-16] 找出你珍视的机会
+151
EP 22
+147
Proxmox VE 安装容器:Ubuntu 20.04
+144
Day 3 云端四大平台比较:AWS . GCP . Azure . Alibaba
有人完赛了!恭喜!!
现在也完成一半了,希望撑得下去。
>>: 连续 30 天 玩玩看 ProtoPie - Day 15
教材网址 https://coding104.blogspot.com/2021/06/java-t...
常听人说前端转後端, 鲜闻人讲後端转前端。 为什麽会想转前端? 好奇心使然、以及很少人做这件事情, ...
tags: ItIron2021 Javascript 前言 昨天我们简单讨论了恼人的强制转型问题,...
这一篇是这一系列 Libraries 比较文实质性的最後一篇了,在下一篇稍做总结以後接着我们就要正...
刚开始学习JavaScript的时候,很单纯的认为所有程序码是逐行执行的,就像看书不都是ㄧ行一行阅读...