Last active
June 18, 2017 00:24
-
-
Save marcolussetti/ddac716e6b2e2bcc15853ff797afdd08 to your computer and use it in GitHub Desktop.
MyTRU CLI client - WORK IN PROGRESS
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python3 | |
import re | |
from datetime import datetime, timezone, timedelta | |
from bs4 import BeautifulSoup | |
import requests | |
# **** CONFIGURATION PARAMS **** | |
mytru_username = "" # MyTRU username | |
mytru_password = "" # MyTRU password | |
def login(username, password): | |
s = requests.session() # Initiates a permanent session | |
# Current time in ms since epoch | |
uuid = (datetime.now(timezone.utc) - datetime(1970, 1, 1, tzinfo=timezone.utc)) // timedelta(microseconds=1) // 1000 | |
# Login | |
r = s.post("https://mytru.tru.ca/cp/home/login", data={"user": username, "pass": password, "uuid": uuid}) | |
r = s.get("https://mytru.tru.ca/cp/home/next") # needs to load this to complete login | |
# TODO: add check for successful login | |
return s | |
def get_transcript(session): | |
# Moving from mytru to banssbprod requires the login thing first or the session won't carry over | |
session.headers.update({"referrer": "https://mytru.tru.ca/render.UserLayoutRootNode.uP"}) | |
r = session.get( | |
"https://mytru.tru.ca/cp/ip/login?sys=sctssb&url=https://banssbprod.tru.ca/banprod/bwskotrn.P_ViewTermTran") | |
# Post to form, it works! | |
r = session.post("https://banssbprod.tru.ca/banprod/bwskotrn.P_ViewTran", data={"levl": "", "tprt": "UN"}) | |
# Return transcript object | |
return Transcript(r.content) | |
class Transcript(object): | |
def __init__(self, html): | |
self.soup = BeautifulSoup(html, "html.parser") | |
self.gpa = self.GPA() | |
self.current_term = self.current_term_grades() | |
print() | |
def GPA(self): | |
transcript_header_row = self.soup.find( | |
string=re.compile("TRANSCRIPT TOTALS \(UNDERGRADUATE\)")).find_parent().find_parent() | |
# We have a starting element, now we got to go 2 down to find the right row | |
results_row = transcript_header_row.find_next_siblings()[1] | |
gpa = results_row.find_all("td")[-1].find("p").text.strip() | |
gpa = float(gpa) | |
return gpa | |
def current_term_grades(self): | |
transcript_header_row = self.soup.find(string=re.compile("COURSES IN PROGRESS")).find_parent().find_parent() | |
if transcript_header_row is not None: | |
# Find the current terms | |
sibling_rows = transcript_header_row.find_next_siblings() | |
current_terms = [] | |
for sibling_row in sibling_rows: | |
current_terms.append(sibling_row.find(string=re.compile("Term:"))) | |
# TODO: remove the None results | |
# print(current_terms[0]) | |
if len(self.soup.find_all(string=str(current_terms[0]))) < 2: | |
return "No grades yet for current term" | |
new_transcript_header_row = self.soup.find( | |
string=str(current_terms[0])).find_parent().find_parent().find_parent() | |
# print(new_transcript_header_row) | |
# TODO: REMOVE THIS BELOW DEBUG LINE | |
# new_transcript_header_row = self.soup.find(string=re.compile("Term: Winter 2017")).find_parent().find_parent().find_parent() | |
# print(new_transcript_header_row) | |
sibling_rows = new_transcript_header_row.find_next_siblings() | |
# Skip the additional standing row(s) | |
pointer = None | |
for sibling_row in sibling_rows: | |
result = sibling_row.find_all(string=re.compile("Additional Standing")) | |
if len(result) > 0: | |
pointer = result[-1] | |
if pointer is not None: | |
sibling_rows = pointer.find_parent().find_parent().find_next_siblings() | |
sibling_rows = sibling_rows[0].find_next_siblings() # Ignores the header for section | |
# Start creating classes | |
courses = [] | |
for row in sibling_rows: | |
# print(row) | |
if len(row.find_all("td")) < 1: | |
break; | |
else: | |
items = row.find_all("td") | |
courses.append(Course(items)) | |
current_term = (str(current_terms[0]).replace("Term: ", ""), courses) | |
return current_term | |
class Course(object): | |
def __init__(self, soup_list): | |
# print(len(soup_list)) | |
self.course_code = soup_list[0].text + soup_list[1].text | |
self.course_name = soup_list[3].text | |
self.course_grade = soup_list[4].text | |
def __repr__(self): | |
return self.course_code + " " + self.course_grade | |
# Main function | |
if __name__ == '__main__': | |
session = login(mytru_username, mytru_password) | |
transcript = get_transcript(session) | |
print("Overall GPA: " + str(transcript.gpa)) | |
print("Results for current term " + transcript.current_term[0] + ": " + str(transcript.current_term[1])) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is a currently in progress work, will need a serious rewrite before it's even remotely suitable for use.