-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcourseTrack.py
More file actions
122 lines (99 loc) · 4.89 KB
/
Copy pathcourseTrack.py
File metadata and controls
122 lines (99 loc) · 4.89 KB
1
2
3
4
5
6
7
8
9
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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as EC
import pyperclip
import time
import easygui
import credentials
import argparse
def getStatus(UNIQUE_ID, FALL, YEAR, show_gui, refresh_interval):
login_url = f'https://utdirect.utexas.edu/apps/registrar/course_schedule/{YEAR}{9 if FALL else 2}/{UNIQUE_ID}/'
options = Options()
if not show_gui: # optional switch to display chrome browser
options.add_argument('--headless')
options.add_argument('--log-level=3')
driver = webdriver.Chrome(options)
print('Authenticating...')
driver.get(login_url)
driver.set_window_size(600,600)
wait = WebDriverWait(driver, 60)
usernameLocate = (By.ID, "username")
passwordLocate = (By.ID, "password")
username_field = wait.until(EC.presence_of_element_located(usernameLocate))
username_field.click()
username_field.send_keys(credentials.USERNAME)
password_field = wait.until(EC.presence_of_element_located(passwordLocate))
password_field.click()
password_field.send_keys(credentials.PASSWORD)
password_field.send_keys(Keys.RETURN)
button_locator = (By.TAG_NAME, "button")
button_field = wait.until(EC.element_to_be_clickable(button_locator))
button_field.click()
print('###### Course Tracker Log ######')
print('PLEASE AUTHENTICATE WITH DUO MOBILE')
button_field = wait.until(EC.element_to_be_clickable(button_locator))
button_field.click()
time.sleep(3) # wait for window to change. If list index out of range error on line 57, increase the sleep timer
last_status = None
driver.minimize_window()
while (True):
className = driver.find_elements(by=By.TAG_NAME, value="h2")[0].text
matches = driver.find_elements(by=By.TAG_NAME, value="td")
cur_status = [ x for x in matches if
x.text == "waitlisted" or
x.text == "open" or
x.text == "open; reserved" or
x.text == "closed"
][0].text
SLEEP_TIME = refresh_interval if refresh_interval else 60 # every minute is the default refresh time
if (cur_status == last_status):
print(f"Unique ID {UNIQUE_ID} is still {last_status}.")
time.sleep(SLEEP_TIME)
driver.refresh()
continue
else:
if (cur_status == "closed"):
print(f"{className} with unique ID {UNIQUE_ID} is currently " + cur_status)
elif cur_status == "cancelled":
print(f"{className} with unique ID {UNIQUE_ID} is cancelled for {YEAR}.")
exit(0)
else:
notifyUser(f"{className} with unique id {UNIQUE_ID} is now {cur_status}!", driver, UNIQUE_ID)
last_status = cur_status
time.sleep(SLEEP_TIME)
driver.refresh()
def notifyUser(body, driver, UNIQUE_ID):
userIn = easygui.ynbox(body + "\nWould you like to go to the registration page?\n\nIf you select \"Yes\", the unique ID will be copied to your clipboard.", "courseTrack", ("Yes", "No"))
if (userIn):
pyperclip.copy(UNIQUE_ID)
goToRegistrationPage(driver)
def goToRegistrationPage(driver):
driver.maximize_window()
registrationURL = "https://utdirect.utexas.edu/registration/chooseSemester.WBX"
#driver.get(registrationURL)
newDriver = driver
newDriver.get(registrationURL)
input("Press Enter to exit...")
exit(0)
def main():
parser = argparse.ArgumentParser(description="Script to periodically check if a current UT course is CLOSED, OPEN, RESERVED, or WAITLISTED. Please invoke the script with the first argument being the course's unique ID number.\n\nEX: python courseTrack.py 50700\n\n")
parser._action_groups.pop()
required = parser.add_argument_group('Required')
optional = parser.add_argument_group('Optional')
required.add_argument('UNIQUE_ID', type=int, help='The 5-digit unique course code')
required.add_argument('SEASON', type=str, help='Fall, spring, or summer')
required.add_argument('YEAR', type=int, help='Current academic year')
optional.add_argument("--show-gui", help = 'Switch to display the selenium chrome driver, usually for debugging.', action="store_true")
optional.add_argument("--refresh-interval", type=int, help="""
Time (sec) between each refresh.
# CAUTION #
Rate limiting may occur when the
interval is set to a value < 2.""")
args = parser.parse_args()
isFall = args.SEASON.upper() == 'FALL'
getStatus(args.UNIQUE_ID, isFall, args.YEAR, args.show_gui, args.refresh_interval)
if __name__ == "__main__":
main()