###### tags: `淡江大學搶課機器人開源專案` # 開源專案230830更新 ## 前言: 搶課機器人在3月放出來後收到廣大的迴響,但最近Chrome更新,修改了呼叫的方式,舊的機器人已經不能使用了,所以這幾天寫了一個新版的並且新增了一些功能,也感謝新生跟轉學生讓我有機會測試,經過測試後可以正常使用,一樣多平台支援,**但intel版的Mac系統晚上才會更新** ## 適用環境: * Mac intel 處理器:**macOS 13.5.1以上都可以使用 * Mac Apple Silicon 處理器:**macOS 13.5.1**以上都可以使用 * Windows 系統:**Windows 10**以上都可以使用 ## 使用方式: ### 1. 先進資料夾下載執行檔案 [下載位置](https://1drv.ms/u/s!AvwcoqTkdjpWg6gp_bPQIFFvSRJ8nQ?e=K7QFC6) > Windows平台請下載Public_WYSHBot_230829_Windows > MacOS Intel處理器的請下載Public_WYSHBot_230829_Mac(intel) > MacOS M1/M2系列處理器請下載Public_WYSHBot_230829_MacOS(Silicon) ### 2. 開始執行搶課機器人 * Windows直接點擊start.bat ![](https://i.imgur.com/EaUWGCb.jpg) * Mac系列直接下載後解壓縮直接放到應用程式資料夾中,點兩下執行 ![](https://i.imgur.com/eiQkxQj.png) * 若Mac無法成功執行請參考備註1 * 在230829有修改圖示,請以實際圖示為主 ### 3. 設定基本資料(Windows/Mac使用方式相同) ![](https://hackmd.io/_uploads/Ska5BE2an.png) * 先設定登入資訊(務必按下儲存登入資訊) * 設定加退選資訊 * 設定完加退選資訊務必按下儲存加退選清單 * **注意,如果沒有使用ChromeDriver的需求,7.就直接使用推薦的不用修改** ### 4. 執行搶課程式(Windows/Mac使用方式相同) ![](https://i.imgur.com/TQmVgpA.png) * 按下執行搶課主程式 ### 5. 設定搶課程式(Windows/Mac使用方式相同) ![](https://hackmd.io/_uploads/B1U5842T2.png) * 先設定語言 * 再設定是要立即搶課或是預約搶課 * 完成後,執行開始搶課 ### 6. 剩下交給上蒼 補充說明:機器人會隨機延遲幾秒鐘,一來是因為學校系統有時候會當機,二來是因為要保障有購買機器人的使用者權利 ### Demo影片: ![](https://i.imgur.com/fHAJqUY.jpg) https://youtu.be/iINclOsUYpI 備註,影片中使用Mac做範例,Windows使用介面大同小異 ### 備註1(開啟任何來源): * 請開啟任終端機: ![](https://i.imgur.com/jJsZZBc.png) * 在終端機中打入以下指令: ![](https://i.imgur.com/Qbtf4bJ.png) sudo spctl --master-disable * 打入密碼(請注意這個密碼不會顯示): ![](https://i.imgur.com/GOy8pHy.png) * 打開設定中的隱私權與安全性: ![](https://i.imgur.com/HiaNSls.png) ## 進階功能 本機器人有Premium版本,提供以下功能: * 完整的搶課速度 * 極速刷課模式 * 單一裝置登入功能 * 帳號密碼加密,強化安全性 ![](https://i.imgur.com/46z1OqC.png) 若有需要,可以點擊以下連結: ![](https://hackmd.io/_uploads/rJ9nP4362.png) ![](https://hackmd.io/_uploads/H1Xb_N3T3.jpg) [https://line.me/ti/g2/EQSB4VBKjoVXM0n46GDIrmdTwieWd1LIrtYpJg?utm_source=invitation&utm_medium=link_copy&utm_campaign=default](https://line.me/ti/g2/EQSB4VBKjoVXM0n46GDIrmdTwieWd1LIrtYpJg?utm_source=invitation&utm_medium=link_copy&utm_campaign=default) ## 原始碼開源 以下為原始碼,可以直接下載原始檔案使用 打包: https://1drv.ms/u/s!AvwcoqTkdjpWg7thc2Y4Pm72H_xErg?e=subqq4 ##### setting.py ``` import os import subprocess import tkinter as tk from tkinter import messagebox from tkinter import ttk from tkinter.constants import * import cryptocode import sys import threading import platform global ScrollBar global window window = tk.Tk() global AddToList_Action AddToList_Action = [] global AddToList_OpenCourse AddToList_OpenCourse = [] global ExchangeFirst ExchangeFirst = 0 global ExchangeSecond ExchangeSecond = 0 global RemoveItem RemoveItem = 0 working_dir = os.path.dirname(os.path.realpath(__file__)) global Login_Path Login_Path = working_dir+"/Module_Addition/ProgramPlugin_1.info" global Selective_Path Selective_Path = working_dir+"/Module_Addition/ProgramPlugin_2.info" global SelectionMode_Path SelectionMode_Path = working_dir+"/Module_Addition/ProgramPlugin_3.info" Record = 0 def LoadTheLoginInformation(): global Record,Login_Path try: with open(Login_Path, 'r') as f: global Login Login = f.read().splitlines() for i in range(len(Login)): if (i+1)==1 or (i+1)==3: pass elif (i+1)==2: global Account_Login_Record Account_Login_Record = str(Login[i])#解密 Account_textbox.insert(0, Account_Login_Record) Record = 1 else: global Password_Login_Record Password_Login_Record = str(Login[i])#解密 Password_textbox.insert(0, Password_Login_Record) except FileNotFoundError: Record = 0 messagebox.showinfo("提示","偵測到程式遭修改\n請聯絡負責人") os._exit() return def LoginSavingInformation(): global Record global Account Account = Account_textbox.get()#加密 #print(Account) Password = Password_textbox.get()#加密 #print(Password) global Login_Path try: if(Account!="" and Password!= ""): with open(Login_Path, 'w') as f: f.write('Account') f.write('\n') f.write(Account) f.write('\n') f.write('Password') f.write('\n') f.write(Password) Record = 1 else: messagebox.showinfo("提示", "輸入錯誤請重試") except: messagebox.showinfo("提示", "我們偵測到了你嘗試修改程式\n請聯絡負責人") os._exit() def SelectiveSaving(): global Selective_Path try: if (Selective_Path): with open(Selective_Path, 'w') as f: f.write('') for i in range(len(AddToList_Action)): with open(Selective_Path, 'a') as f: f.write(AddToList_Action[i]) f.write('\n') f.write(AddToList_OpenCourse[i]) f.write('\n') messagebox.showinfo("提示","選課清單儲存成功") else: messagebox.showinfo("提示","儲存路徑錯誤請重試") except: messagebox.showinfo("提示", "我們偵測到了您嘗試修改過程式\n請聯絡搶課負責人") return def LoadSelectivedList(): global Selective_Path try: with open(Selective_Path, 'r') as f: global Selection Selection = f.read().splitlines() for i in range(len(Selection)): if (i+1)%2==1: AddToList_Action.append(str(Selection[i])) elif (i+1)%2==0: AddToList_OpenCourse.append(str(Selection[i])) except FileNotFoundError: pass return def LoginInformatioSavingConfirmBox(): global Record Account = Account_textbox.get() Password = Password_textbox.get() if (Record==1 and Account !="" and Password !=""): LoginSavingInformation() messagebox.showinfo("提示", "密碼更新成功") elif Account =="" or Password =="": messagebox.showinfo("提示", "學號或密碼不能留空") elif (Record==0 and Account !="" and Password !=""): '''MsgBox = tk.messagebox.askquestion("提示","請問你確定儲存學號密碼嗎?\n學號只能綁定一次喔!\n學號未來是不能修改\n\nP.S.密碼可以修改") if MsgBox =="yes": LoginSavingInformation() Account_textbox.config(state='disable') messagebox.showinfo("提示", "學號密碼設定成功") else: pass''' messagebox.showinfo("提示", "學號密碼設定成功") def build_GUI(): #Build A GUI Window window.title("選課設定") window.geometry('380x540') window.resizable(False, True) #LoginTitle LoginTitle = tk.Label(window,width=30,text="登入資訊",font=("normal",15),compound="center") LoginTitle.place(x=190,y=20,anchor=CENTER) AccountInformation() PasswordInformation() #Button #LoginSaving Button Save_Button = tk.Button(text="儲存登入資訊",command=LoginInformatioSavingConfirmBox) Save_Button.place(x=190, y=115, anchor=CENTER) LoadTheLoginInformation() #SelectiveSaving_Button #SelectiveTitle SelectiveTitle = tk.Label(width=30,text="加退選資訊",font=("normal",15),compound="center") SelectiveTitle.place(x=190, y=165, anchor=CENTER) LoadSelectivedList() showList() Options() window.mainloop() #Login Information def AccountInformation(): #Account Label_Account_textbox = tk.Label(width=6,text="學號",compound="center") Label_Account_textbox.place(x=60,y=40) global Account_textbox Account_textbox = tk.Entry(window) Account_textbox.pack() Account_textbox.place(x=120,y=40) def PasswordInformation(): # Password Label_Password_textbox = tk.Label(width=6, text="密碼", compound="center") Label_Password_textbox.place(x=60,y=70) global Password_textbox Password_textbox = tk.Entry(window) Password_textbox.pack() Password_textbox.place(x=120,y=70) #Action def Drop(): Remove_Target = int(Revise_Remove_Box.get()) - 1 if (Remove_Target<len(AddToList_Action) and Remove_Target>=0): initial() AddToList_Action.pop(Remove_Target) AddToList_OpenCourse.pop(Remove_Target) #Clear TextBox Revise_Remove_Box.delete(0, END) showList() #messagebox.showinfo("提示", "刪除成功") else: messagebox.showinfo("提示", "輸入錯誤,請重試") return def Exchange(): FirstIndex = int(Revise_ExchangeFirst_Box.get()) - 1 SecondIndex = int(Revise_ExchangeSecond_Box.get()) - 1 if (FirstIndex < len(AddToList_Action) and FirstIndex >= 0 and SecondIndex < len(AddToList_Action) and SecondIndex >= 0 and SecondIndex!= FirstIndex): AddToList_Action[FirstIndex], AddToList_Action[SecondIndex] = AddToList_Action[SecondIndex], AddToList_Action[FirstIndex] AddToList_OpenCourse[FirstIndex], AddToList_OpenCourse[SecondIndex] = AddToList_OpenCourse[SecondIndex], AddToList_OpenCourse[FirstIndex] # Clear TextBox Revise_ExchangeFirst_Box.delete(0, END) Revise_ExchangeSecond_Box.delete(0, END) showList() messagebox.showinfo("提示", "交換成功") else: messagebox.showinfo("提示", "輸入錯誤,請重試") return def initial(): y_axis = 270 for i in range(len(AddToList_Action)): y_axis = y_axis + 30 temp = tk.Label(window,width=2,height=3,text="",font=("normal",10),compound="center") temp.pack() temp.place(x=55,y=y_axis,anchor=CENTER) temp_1 = tk.Label(window,width=7,height=3,text="",font=("normal",10),compound="center") temp_1.pack() temp_1.place(x=100,y=y_axis,anchor=CENTER) temp_2 = tk.Label(window, width=7,height=3,text="", font=("normal",10),compound="center") temp_2.pack() temp_2.place(x=170, y=y_axis,anchor=CENTER) #Selective Information def Options(): # Options global Optional_Selective Optional_Selective = ttk.Combobox(window,state="readonly", width=5, values=["加選", "退選"]) Optional_Selective.pack() Optional_Selective.place(x=100, y=195, anchor=CENTER) Optional_Selective.current(0) #OpenCourseBox global OpenCourseBox OpenCourseBox = tk.Entry(window,width=15) OpenCourseBox.pack() OpenCourseBox.place(x=220,y=195,anchor=CENTER) #AddButton AddButton = tk.Button(text="加入清單",command=AddToList) AddButton.place(x=190, y=225, anchor=CENTER) #================================================================================================================ #List Number_Column = tk.Label(window,width=2,height=3,text="#",font=("normal",10),compound="center") Number_Column.pack() Number_Column.place(x=55,y=270,anchor=CENTER) Action_Column = tk.Label(window,width=7,height=3,text="操作",font=("normal",10),compound="center") Action_Column.pack() Action_Column.place(x=100,y=270,anchor=CENTER) CourseCode_Column = tk.Label(window, width=7,height=3, font=("normal",10), text="開課代碼",compound="center") CourseCode_Column.pack() CourseCode_Column.place(x=170, y=270,anchor=CENTER) #================================================================================================================ #ReviseArea #ReviseTitle Revise_Column = tk.Label(window, width=20, height=3, font=("normal", 10), text="調整", compound="center") Revise_Column.pack() Revise_Column.place(x=300, y=270, anchor=CENTER) #ReviseFirst_# Revise_ExchangeFirst = tk.Label(window, width=2, height=1, font=("normal", 10), text="#", compound="center") Revise_ExchangeFirst.pack() Revise_ExchangeFirst.place(x=220, y=300, anchor=CENTER) #ReviseFirst_TextBox global Revise_ExchangeFirst_Box Revise_ExchangeFirst_Box = tk.Entry(window, width=3) Revise_ExchangeFirst_Box.pack() Revise_ExchangeFirst_Box.place(x=240, y=300, anchor=CENTER) #ReviseSecond_# Revise_ExchangeSecond = tk.Label(window, width=2, height=1, font=("normal", 10), text="#", compound="center") Revise_ExchangeSecond.pack() Revise_ExchangeSecond.place(x=270, y=300, anchor=CENTER) #ReviseSecond_TextBox global Revise_ExchangeSecond_Box Revise_ExchangeSecond_Box = tk.Entry(window, width=3) Revise_ExchangeSecond_Box.pack() Revise_ExchangeSecond_Box.place(x=290, y=300, anchor=CENTER) #ExchangeButton ExchangeButton = tk.Button(text="交換", command=Exchange) ExchangeButton.place(x=340, y=300, anchor=CENTER) #Remove_# Revise_Remove = tk.Label(window, width=2, height=1, font=("normal", 10), text="#", compound="center") Revise_Remove.pack() Revise_Remove.place(x=250, y=330, anchor=CENTER) #Remove_TextBox global Revise_Remove_Box Revise_Remove_Box = tk.Entry(window, width=3) Revise_Remove_Box.pack() Revise_Remove_Box.place(x=275, y=330, anchor=CENTER) #Remove_Button Remove_Button = tk.Button(text=U"刪除", command=Drop) Remove_Button.place(x=330, y=330, anchor=CENTER) #================================================================================================================ #Saving Area #SavingTitle Saving_Column = tk.Label(window, width=20, height=2, font=("normal", 10), text=U"儲存", compound="center") Saving_Column.pack() Saving_Column.place(x=300, y=370, anchor=CENTER) #SavingButton SavingButton = tk.Button(text=U"儲存加退選清單", command=SelectiveSaving) SavingButton.place(x=300, y=390, anchor=CENTER) # ================================================================================================================ # Execution Area # ExecutionTitle Execution_Column = tk.Label(window, width=20, height=2, font=("normal", 10), text=U"搶課", compound="center") Execution_Column.pack() Execution_Column.place(x=300, y=420, anchor=CENTER) # ExecutionButton global Execution_Mode Execution_Mode = ttk.Combobox(window, state="readonly", width=15, values=["UC模式(推薦)","ChromeDriver"]) Execution_Mode.pack() Execution_Mode.place(x=300, y=450, anchor=CENTER) Execution_Mode.current(0) ExecutionButton = tk.Button(text=U"執行搶課主程式", command=ExecutionMainFunction) ExecutionButton.place(x=300, y=480, anchor=CENTER) def AddToList(): if Optional_Selective.get() == "加選" and OpenCourseBox.get() !="": AddToList_Action.append("Add") AddToList_OpenCourse.append(OpenCourseBox.get()) OpenCourseBox.delete(0, END) showList() elif Optional_Selective.get() == "退選" and OpenCourseBox.get() !="": AddToList_Action.append("Remove") AddToList_OpenCourse.append(OpenCourseBox.get()) OpenCourseBox.delete(0, END) showList() elif Optional_Selective.get() == "刷課" and OpenCourseBox.get() !="": AddToList_Action.append("Cycle") AddToList_OpenCourse.append(OpenCourseBox.get()) OpenCourseBox.delete(0, END) showList() else: messagebox.showinfo("提示","開課代碼不能為空白") def showList(): y_axis = 270 for i in range(len(AddToList_Action)): y_axis = y_axis + 30 temp = tk.Label(window,width=2,height=3,text=i+1,font=("normal",10),compound="center") temp.pack() temp.place(x=55,y=y_axis,anchor=CENTER) temp_1 = tk.Label(window,width=7,height=3,text=AddToList_Action[i],font=("normal",10),compound="center") temp_1.pack() temp_1.place(x=100,y=y_axis,anchor=CENTER) temp_2 = tk.Label(window, width=7,height=3,text=AddToList_OpenCourse[i], font=("normal",10),compound="center") temp_2.pack() temp_2.place(x=170, y=y_axis,anchor=CENTER) #print(y_axis) if (y_axis>=480): wide = 380 height = str(540+(len(AddToList_Action)-7)*30) mix = str(wide)+"x"+height window.geometry(mix) return def LoginInformationCheck(): CurrentAccount = Account_textbox.get() CurrentPassword = Password_textbox.get() global Login_Path with open(Login_Path, 'r') as f: global Login Login = f.read().splitlines() for i in range(len(Login)): if (i + 1) == 1 or (i + 1) == 3: pass elif (i + 1) == 2: global Account_Login_Record Account_Login_Record = str(Login[i]) # 解密 else: global Password_Login_Record Password_Login_Record = str(Login[i]) # 解密 try: if Account_Login_Record != CurrentAccount or Password_Login_Record != CurrentPassword : messagebox.showinfo("提示", "請儲存帳號密碼") return False except NameError: messagebox.showinfo("提示", "請設定帳號密碼") return False return True def launch_MainFunction(): try: subprocess.Popen(working_dir + "/Module_Addition/main", shell=True) except: subprocess.Popen(working_dir + "/Module_Addition/main.exe", shell=True) def ExecutionMainFunction(): if(LoginInformationCheck()): global working_dir,SelectionMode_Path if(Execution_Mode.get()=="UC模式(推薦)"): with open(SelectionMode_Path, 'w') as f: f.write('') f.write('UCMode') else: with open(SelectionMode_Path, 'w') as f: f.write('') f.write('ChromeDriverMode') if hasattr(sys, 'frozen'): threading.Thread(target=launch_MainFunction).start() else: try: s = subprocess.Popen(['python3', 'main' + '.py'], cwd=working_dir+'/Module_Addition') except: s = subprocess.Popen(['python', 'main' + '.py'], cwd=working_dir+'/Module_Addition') else: pass #main function if __name__ == '__main__': build_GUI() ``` ##### main.py ``` import os import datetime import os import random import ssl import time import tkinter as tk from tkinter import messagebox from tkinter import ttk from tkinter.constants import * from tkinter import filedialog import cryptocode from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.chrome.service import Service as ChromeService import chromedriver_autoinstaller ssl._create_default_https_context = ssl._create_unverified_context URL_Chinese = "https://www.ais.tku.edu.tw/EleCos/login.aspx?ReturnUrl=%2felecos%2f" URL_English = "https://www.ais.tku.edu.tw/EleCos_English/loginE.aspx" global ChineseScript ChineseScript = "javascript: (function(){ var numHash={b6589fc6ab0dc82cf12099d1c2d40ab994e8410c:\"0\",\"356a192b7913b04c54574d18c28d46e6395428ab\":\"1\",da4b9237bacccdf19c0760cab7aec4a8359010b0:\"2\",\"77de68daecd823babbb58edb1c8e14d7106e83bb\":\"3\",\"1b6453892473a467d07372d45eb05abc2031647a\":\"4\",ac3478d69a3c81fa62e60f5c3696165a4e5e6ac4:\"5\",c1dfd96eea8cc2b62785275bca38ac261256e278:\"6\",\"902ba3cda1883801594b6e1b452790cc53948fda\":\"7\",fe5dbbcea5ce7e2988b8c69bcfdfde8904aabc1f:\"8\",\"0ade7c2cf97f75d009975f4d720d1fa6c19f4897\":\"9\"};$.ajax({url:\"https://www.ais.tku.edu.tw/EleCos/Handler1.ashx\",type:\"post\",async:false,success:function(voice){document.getElementById(\"txtCONFM\").value=numHash[voice[0]]+numHash[voice[1]]+numHash[voice[2]]+numHash[voice[3]]+numHash[voice[4]]+numHash[voice[5]];}}); })();" global EnglishScript EnglishScript = "javascript: (function(){ var numHash={b6589fc6ab0dc82cf12099d1c2d40ab994e8410c:\"0\",\"356a192b7913b04c54574d18c28d46e6395428ab\":\"1\",da4b9237bacccdf19c0760cab7aec4a8359010b0:\"2\",\"77de68daecd823babbb58edb1c8e14d7106e83bb\":\"3\",\"1b6453892473a467d07372d45eb05abc2031647a\":\"4\",ac3478d69a3c81fa62e60f5c3696165a4e5e6ac4:\"5\",c1dfd96eea8cc2b62785275bca38ac261256e278:\"6\",\"902ba3cda1883801594b6e1b452790cc53948fda\":\"7\",fe5dbbcea5ce7e2988b8c69bcfdfde8904aabc1f:\"8\",\"0ade7c2cf97f75d009975f4d720d1fa6c19f4897\":\"9\"};$.ajax({url:\"https://www.ais.tku.edu.tw/EleCos_English/Handler1.ashx\",type:\"post\",async:false,success:function(voice){document.getElementById(\"txtCONFM\").value=numHash[voice[0]]+numHash[voice[1]]+numHash[voice[2]]+numHash[voice[3]]+numHash[voice[4]]+numHash[voice[5]];}}); })();" global window window = tk.Tk() global AddToList_Action AddToList_Action = [] global AddToList_OpenCourse AddToList_OpenCourse = [] Account_Login_Record = 0 Password_Login_Record = 0 working_dir = os.path.dirname(os.path.realpath(__file__)) global Login_Path Login_Path = working_dir+"/ProgramPlugin_1.info" global Selective_Path Selective_Path = working_dir+"/ProgramPlugin_2.info" global SelectionMode_Path SelectionMode_Path = working_dir+"/ProgramPlugin_3.info" chromedriver_autoinstaller.install() global SelectionMode global driver # Check select Mode with open(SelectionMode_Path, 'r') as f: global SelectionMode SelectionMode = f.read().splitlines() SelectionMode = str(SelectionMode[0]) def OpenChrome(): global driver,Driver_Path if (SelectionMode == "UCMode"): service = ChromeService() options = webdriver.ChromeOptions() driver = webdriver.Chrome(service=service,options=options) else: messagebox.showinfo("提示", "請選取ChromeDriver檔案") ChromeDriver_path = filedialog.askopenfilename() # 選擇檔案後回傳檔案路徑與名稱 service = ChromeService(executable_path=ChromeDriver_path) # print(ChromeDriver_path) driver = webdriver.Chrome(service=service) def LoadTheLoginInformation(): global Login_Path try: with open(Login_Path, 'r') as f: global Login Login = f.read().splitlines() for i in range(len(Login)): if (i+1)==1 or (i+1)==3: pass elif (i+1)==2: global Account_Login_Record Account_Login_Record = str(Login[i]) #print("Account: "+Account_Login_Record,type(Account)) #print(line[i],type(line[i])) else: global Password_Login_Record Password_Login_Record = str(Login[i]) #print("Password: "+Password_Login_Record) except FileNotFoundError: messagebox.showinfo("提示", "無法載入登入資訊"+"\n"+"請先執行setting設定加退選資訊") if len(Login)==0: messagebox.showinfo("提示","沒有登入資訊"+"\n"+"請先執行setting設定登入資訊") return def LoadTheSelectionInformation(): global Selective_Path try: with open(Selective_Path, 'r') as f: global Selection Selection = f.read().splitlines() for i in range(len(Selection)): if (i+1)%2==1: if str(Selection[i]) =="Add" or str(Selection[i]) =="Remove": AddToList_Action.append(str(Selection[i])) elif str(Selection[i]) =="Cycle": pass elif (i+1)%2==0: AddToList_OpenCourse.append(str(Selection[i])) else: pass except FileNotFoundError: messagebox.showinfo("提示", "無法載入加退選清單"+"\n"+"請先執行setting設定加退選資訊") os._exit() if len(Selection)==0: messagebox.showinfo("提示","加退選清單為空白"+"\n"+"請先執行setting設定加退選資訊") os._exit() return def build_GUI(): #Build A GUI Window LoadTheLoginInformation() LoadTheSelectionInformation() window.title("搶課程式") window.geometry('380x440') window.resizable(False, True) #LanguageTitle LanguageTitle = tk.Label(window,width=30,text="語言選擇",font=("normal",15),compound="center") LanguageTitle.place(x=190,y=20,anchor=CENTER) LanguageSelect() #TimeTitle SelectiveTitle = tk.Label(window,width=30,text="搶課排程",font=("normal",15),compound="center") SelectiveTitle.place(x=190, y=80, anchor=CENTER) TimeMode() initial() #Execution Button ExecutionButton = tk.Button(window,text="開始搶課", command=Execution) ExecutionButton.place(x=190, y=320, anchor=CENTER) #AboutMe AboutMeTitle = tk.Label(window, text="~本機器人由淡江大學 資汛工程學系 WYSH 開發製作~", font=("normal", 10), compound="center") AboutMeTitle.place(x=190, y=350, anchor=CENTER) CompilerTitle = tk.Label(window, text="使用Python3.11.4開發製作,2023/08/28編譯", font=("normal", 10),compound="center") CompilerTitle.place(x=190, y=370, anchor=CENTER) SloganTitle = tk.Label(window, text="電腦怪傑,實力不容小覷,不服來戰", font=("normal", 10),compound="center") SloganTitle.place(x=190, y=390, anchor=CENTER) SloganTitle_2 = tk.Label(window, text="只有不想搶的課,沒有搶不到的課", font=("normal", 10), compound="center") SloganTitle_2.place(x=190, y=410, anchor=CENTER) window.mainloop() def LanguageSelect(): global var_1 var_1 = tk.StringVar() global Language_Chinese, Language_English Language_Chinese = tk.Radiobutton(window,text='中文', command=LaguageSet,var=var_1, value=1) Language_English = tk.Radiobutton(window,text='English', command=LaguageSet,var=var_1, value=2) Language_Chinese.place(x=100, y=30) Language_English.place(x=220, y=30) def LaguageSet(): global SelectionMode global Language_Set global driver Language_Set = var_1.get() if Language_Set=="1": driver.get(URL_Chinese) else: driver.get(URL_English) return def TimeMode(): global var_2 var_2 = tk.StringVar() global TimeMode_Immediately, TimeMode_Schedule TimeMode_Immediately = tk.Radiobutton(window,text='立即',command=TimeModeSet, var=var_2,value=3) TimeMode_Schedule = tk.Radiobutton(window,text='預約搶課',command=TimeModeSet, var=var_2,value=4) TimeMode_Immediately.place(x=100, y=100) TimeMode_Schedule.place(x=220, y=100) def TimeModeSet(): global TimeMode_Set TimeMode_Set = var_2.get() if TimeMode_Set =="3": initial() else: TimeSetArea() return def initial(): # TimeAreaTitle TimeAreaTitle = tk.Label(window,width=30, state="disable",text="時間設定", font=("normal", 15), compound="center") TimeAreaTitle.place(x=190, y=150, anchor=CENTER) # YearTitle YearTitle = tk.Label(window,width=3, state="disable", text="年份", font=("normal", 10), compound="center") YearTitle.place(x=80, y=180, anchor=CENTER) # YearSelectionBox global YearSelection YearSelection = ttk.Combobox(window, state="disable", width=4, values=["2023", "2024", "2025", "2026", "2027", "2028", "2029", "2030"]) YearSelection.pack() YearSelection.place(x=75, y=200, anchor=CENTER) YearSelection.current(0) # MonthTitle MonthTitle = tk.Label(window,width=3, state="disable", text="月份", font=("normal", 10), compound="center") MonthTitle.place(x=125, y=180, anchor=CENTER) # MonthSelectionBox global MonthSelection MonthSelection = ttk.Combobox(window, state="disable", width=2, values=["01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12"]) MonthSelection.pack() MonthSelection.place(x=125, y=200, anchor=CENTER) MonthSelection.current(0) # DateTitle DateTitle = tk.Label(window,width=3, state="disable", text="日期", font=("normal", 10), compound="center") DateTitle.place(x=170, y=180, anchor=CENTER) # DateSelectionBox global DateSelection DateSelection = ttk.Combobox(window, state="disable", width=2, values=["01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31"]) DateSelection.pack() DateSelection.place(x=170, y=200, anchor=CENTER) DateSelection.current(10) # HourTitle HourTitle = tk.Label(window,width=3, state="disable", text="小時", font=("normal", 10), compound="center") HourTitle.place(x=225, y=180, anchor=CENTER) # HourSelectionBox global HourSelection HourSelection = ttk.Combobox(window, state="disable", width=2, values=["00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23"]) HourSelection.pack() HourSelection.place(x=225, y=200, anchor=CENTER) HourSelection.current(12) # MinutesTitle MinutesTitle = tk.Label(window,width=3, state="disable", text="分", font=("normal", 10), compound="center") MinutesTitle.place(x=270, y=180, anchor=CENTER) # MinutesSelectionBox global MinutesSelection MinutesSelection = ttk.Combobox(window, state="disable", width=2, values=["00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "50", "51", "52", "53", "54", "55", "56", "57", "58", "59"]) MinutesSelection.pack() MinutesSelection.place(x=270, y=200, anchor=CENTER) MinutesSelection.current(30) # SecondTitle SecondTitle = tk.Label(window,width=3, state="disable", text="秒", font=("normal", 10), compound="center") SecondTitle.place(x=315, y=180, anchor=CENTER) # SecondSelectionBox global SecondSelection SecondSelection = ttk.Combobox(window, state="disable", width=2, values=["00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "50", "51", "52", "53", "54", "55", "56", "57", "58", "59"]) SecondSelection.pack() SecondSelection.place(x=315, y=200, anchor=CENTER) SecondSelection.current(0) return def TimeSetArea(): # TimeAreaTitle TimeAreaTitle = tk.Label(window,width=30, state="normal",text="時間設定", font=("normal", 15), compound="center") TimeAreaTitle.place(x=190, y=150, anchor=CENTER) #YearTitle YearTitle = tk.Label(window,width=3, state="normal", text="年份", font=("normal", 10), compound="center") YearTitle.place(x=80, y=180, anchor=CENTER) #YearSelectionBox global YearSelection YearSelection = ttk.Combobox(window, state="readonly",width=4,values=["2023","2024","2025","2026","2027","2028","2029","2030"]) YearSelection.pack() YearSelection.place(x=75, y=200, anchor=CENTER) YearSelection.current(0) #MonthTitle MonthTitle = tk.Label(window,width=3, state="normal", text="月份", font=("normal", 10), compound="center") MonthTitle.place(x=125, y=180, anchor=CENTER) #MonthSelectionBox global MonthSelection MonthSelection = ttk.Combobox(window, state="readonly", width=2,values=["01", "02", "03", "04", "05", "06", "07", "08","09","10","11","12"]) MonthSelection.pack() MonthSelection.place(x=125, y=200, anchor=CENTER) MonthSelection.current(0) #DateTitle DateTitle = tk.Label(window,width=3, state="normal", text="日期", font=("normal", 10), compound="center") DateTitle.place(x=170, y=180, anchor=CENTER) #DateSelectionBox global DateSelection DateSelection = ttk.Combobox(window, state="readonly", width=2, values=["01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12","13","14","15","16","17","18","19","20","21","22","23","24","25","26","27","28","29","30","31"]) DateSelection.pack() DateSelection.place(x=170, y=200, anchor=CENTER) DateSelection.current(10) #HourTitle HourTitle = tk.Label(window,width=3, state="normal", text="小時", font=("normal", 10), compound="center") HourTitle.place(x=225, y=180, anchor=CENTER) #HourSelectionBox global HourSelection HourSelection = ttk.Combobox(window, state="readonly", width=2,values=["00","01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13","14", "15", "16", "17", "18", "19", "20", "21", "22", "23"]) HourSelection.pack() HourSelection.place(x=225, y=200, anchor=CENTER) HourSelection.current(12) #MinutesTitle MinutesTitle = tk.Label(window,width=3, state="normal", text="分", font=("normal", 10), compound="center") MinutesTitle.place(x=270, y=180, anchor=CENTER) #MinutesSelectionBox global MinutesSelection MinutesSelection = ttk.Combobox(window, state="readonly", width=2, values=["00","01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24","25","26","27","28","29","30","31","32","33","34","35","36","37","38","39","40","41","42","43","44","45","46","47","48","49","50","51","52","53","54","55","56","57","58","59"]) MinutesSelection.pack() MinutesSelection.place(x=270, y=200, anchor=CENTER) MinutesSelection.current(30) # SecondTitle SecondTitle = tk.Label(window,width=3, state="normal", text="秒", font=("normal", 10), compound="center") SecondTitle.place(x=315, y=180, anchor=CENTER) #SecondSelectionBox global SecondSelection SecondSelection = ttk.Combobox(window, state="readonly", width=2, values=["00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "50", "51", "52", "53", "54", "55", "56", "57", "58", "59"]) SecondSelection.pack() SecondSelection.place(x=315, y=200, anchor=CENTER) SecondSelection.current(0) return def Execution(): global driver try: Account(Account_Login_Record) Password(Password_Login_Record) ConfirmNumber() if TimeMode_Set=="3": driver.find_element("xpath", "//*[@id=\"btnLogin\"]").click() # 時間到了會自動幫你按登入 Selection_Main() else: TimeSet = YearSelection.get()+"-"+MonthSelection.get()+"-"+DateSelection.get()+" "+HourSelection.get()+":"+MinutesSelection.get()+":"+SecondSelection.get()#str(int(SecondSelection.get())+1) TimeCheck(TimeSet) Selection_Main() except: pass return def Selection_Main(): for i in range(len(AddToList_Action)): if AddToList_Action[i]=="Add": AddCourse(AddToList_OpenCourse[i]) elif AddToList_Action[i]=="Remove": RemoveCourse(AddToList_OpenCourse[i]) else: pass #Login information #StudentID def Account(Account_Number): global driver try: account = driver.find_element("xpath","//*[@id=\"txtStuNo\"]") account.clear() account.send_keys(Account_Number)#學號 except: print("系統尚未開放") return #StudentPassword def Password(Password_Value): global driver try: password = driver.find_element("xpath","//*[@id=\"txtPSWD\"]") password.clear() password.send_keys(Password_Value)#密碼 except: print("系統尚未開放") return def ConfirmNumber(): global driver #ConfirmNumber #try: ConfirmNumber = driver.find_element("xpath","//*[@id=\"txtCONFM\"]") ConfirmNumber.clear() try: if Language_Set=="1": driver.execute_script(ChineseScript) else: driver.execute_script(EnglishScript) except: ConfirmNumber.send_keys("") return def TimeCheck(TIME_SET): global driver #Check the time #格式'2023-01-11 12:29:59' #確認加選時間,但拜託格式不要改,空格不要刪除 try: localtime = time.localtime() global result result = time.strftime("%Y-%m-%d %H:%M:%S", localtime) year_check = result[0]+result[1]+result[2]+result[3] month_check = result[5]+result[6] date_check = result[8]+result[9] hour_check = result[11]+result[12] minutes_check = result[14]+result[15] seconds_check = result[17]+result[18] RandomNumber = random.randrange(11) current = datetime.datetime(int(year_check),int(month_check),int(date_check),int(hour_check),int(minutes_check),int(seconds_check)) selection_time_set = datetime.datetime(int(YearSelection.get()),int(MonthSelection.get()),int(DateSelection.get()),int(HourSelection.get()),int(MinutesSelection.get()),int(SecondSelection.get())+RandomNumber) #print(current<selection_time_set) while current<=selection_time_set: localtime = time.localtime() result = time.strftime("%Y-%m-%d %H:%M:%S", localtime) year_check = result[0] + result[1] + result[2] + result[3] month_check = result[5] + result[6] date_check = result[8] + result[9] hour_check = result[11] + result[12] minutes_check = result[14] + result[15] seconds_check = result[17] + result[18] current = datetime.datetime(int(year_check), int(month_check), int(date_check), int(hour_check),int(minutes_check), int(seconds_check)) print(result) time.sleep(1) driver.refresh() Account(Account_Login_Record) Password(Password_Login_Record) ConfirmNumber() #Login driver.find_element("xpath", "//*[@id=\"btnLogin\"]").click() # 時間到了會自動幫你按登入 print("LoginTime: "+result) except: driver.find_element("xpath", "//*[@id=\"btnLogin\"]").click() # 時間到了會自動幫你按登入 print("已經嘗試登入") return def RemoveCourse(OpenCode): global driver #Remove #要刪除的課程 try: Remove_Number = driver.find_element("xpath","//*[@id=\"txtCosEleSeq\"]") Remove_Number.clear() Remove_Number.send_keys(OpenCode) #""不要刪掉 driver.find_element("xpath","//*[@id=\"btnDel\"]").click() except: #messagebox.showinfo("提示","系統尚未開放,請耐心等學校開放") print("系統尚未開放,退選失敗") return def AddCourse(OpenCode): global driver #Add RandomNumber = random.randrange(3) time.sleep(RandomNumber) #要加的課程 try: Add_Number = driver.find_element("xpath","//*[@id=\"txtCosEleSeq\"]") Add_Number.clear() Add_Number.send_keys(OpenCode) #""不要刪掉 driver.find_element("xpath","//*[@id=\"btnAdd\"]").click() except: #messagebox.showinfo("提示", "系統尚未開放,請耐心等學校開放") try: driver.find_element("xpath", "//*[@id=\"btnReLogin\"]").click() # 按下重新登入 Account(Account_Login_Record) Password(Password_Login_Record) ConfirmNumber() driver.find_element("xpath", "//*[@id=\"btnLogin\"]").click() #按下登入 except: pass return def ShowCurrentTable(): global driver #Show the all Class that you have selected driver.find_element("xpath","//*[@id=\"btnEleCos\"]").click() #============================================================================================ #main function #messagebox.showinfo("提示",working_dir) if __name__ == '__main__': OpenChrome() build_GUI() ```