iT邦幫忙

2021 iThome 鐵人賽

DAY 16
1
Modern Web

JavaScript Easy Go!系列 第 16

#16 Automation (4)

今天寫第二步「進入選課頁面」、第三步「至加選頁面」及第四步「查詢你想要的課程」。

enter

這個函式涵蓋了第二步及第三步,因為不想分太多函式。

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

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

其實就是完全擬人的步驟,畢竟是自動化嘛!

好混喔

明天應該會比較東西啦!
應該吧?


每日鐵人賽熱門 Top 10 (0929)

以 9/29 20:00 ~ 9/30 20:00 文章觀看數增加值排名

  1. +284 讓程式碼化為 API Doc
    • 作者: Chris
    • 系列:Vue.js 進階心法
  2. +273 終章 - 資安碎碎念與心得
    • 作者: John醬
    • 系列:網路奇妙物語 - IT&Security
  3. +224 [Day 28] 資料產品開發實務 - 非機器學習模型
    • 作者: bryanyang0528
    • 系列:資料產品開發與專案管理
  4. +205 Day 1 無限手套 AWS 版:掌控一切的 5 + 1 雲端必學主題
    • 作者: 用圖片高效學程式
    • 系列:無限手套 AWS 版:掌控一切的 5 + 1 雲端必學主題
  5. +197 [Day30] 完結灑花❀ 看完賽心得順便用Python畫 3D 漸層花朵!
    • 作者: lulu_meat
    • 系列:奇怪的知識增加了!原來程式還可以這樣用?!
  6. +179 [重構倒數第30天] - 使用 Vue3 Composition API 重構 JS 選單
    • 作者: MikeCheng
    • 系列:[ 重構倒數30天,你的網站不Vue白不Vue ]
  7. +178 [DAY-16] 找出你珍視的機會
    • 作者: flipsyde
    • 系列:帶腦去上班 & No Rules Rules
  8. +151 EP 22
    • 作者: James Tsai
    • 系列:Re: 從零開始用 Xamarin 技術來復刻過去開發的一個 App : TopStore
  9. +147 Proxmox VE 安裝容器:Ubuntu 20.04
    • 作者: Jason Cheng (節省哥)
    • 系列:突破困境:企業開源虛擬化管理平台
  10. +144 Day 3 雲端四大平台比較:AWS . GCP . Azure . Alibaba
    • 作者: 用圖片高效學程式
    • 系列:無限手套 AWS 版:掌控一切的 5 + 1 雲端必學主題

有人完賽了!恭喜!!
現在也完成一半了,希望撐得下去。


上一篇
#15 Automation (3)
下一篇
#17 Automation (5)
系列文
JavaScript Easy Go!31

尚未有邦友留言

立即登入留言