import requests from urllib.parse import urlparse, parse_qs import re from bs4 import BeautifulSoup, NavigableString import random session = requests.Session() session.headers.update({ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:130.0) Gecko/20100101 Firefox/130.0' }) class LVA: def __init__(self, id: str, name: str, ects: float, curricula: list[str], type: str): self.id = id self.name = name self.ects = ects self.curricula = curricula self.type = type def id_pretty(self): # format 123123 -> 123.123 return f'{self.id[:3]}.{self.id[3:]}' def __str__(self): return f'{self.name} ({self.id}) - {self.ects} ECTS' def __repr__(self): return f'{self.name} ({self.id})' def get_direct_text_clean(element): text = ''.join(child for child in element.children if isinstance(child, NavigableString)) return re.sub(r'\s+', ' ', text).strip() def gen_request_tokens(): request_token = str(random.randint(0, 999)) window_id = str(random.randint(0, 999)) session.cookies.set(f"dsrwid-{request_token}", window_id) return (request_token, window_id) class TISS: @staticmethod def get_anonymous_tiss_link(code: str): return f"https://tiss.tuwien.ac.at/course/courseDetails.xhtml?courseNr={code}" @staticmethod def get_lva(code: str): tokens = gen_request_tokens() res = session.get(f"https://tiss.tuwien.ac.at/course/courseDetails.xhtml?courseNr={code}&dsrid={tokens[0]}&dswid={tokens[1]}") soup = BeautifulSoup(res.text, 'html.parser') course_name = get_direct_text_clean(soup.select('#contentInner > h1')[0]) subheader = soup.select('#subHeader')[0].text ects = float(re.search(r'(\d+\.\d+)EC', subheader).group(1)) # extract "VU" from "2024W, VU, 2.0h, 3.0EC" type = subheader.split(",")[1].strip() table = soup.select('th[aria-label="Studienkennzahl"]')[0].parent.parent.parent curricula = [re.sub("\D", "", tr.find("td").text) for tr in table.find("tbody").find_all("tr")] lva = LVA(code, course_name, ects, curricula, type) return lva @staticmethod def get_code_from_any(any: str): # Example: https://tiss.tuwien.ac.at/course/courseDetails.xhtml?dswid=5304&dsrid=381&courseNr=180771&semester=2024W any = any.strip() url = urlparse(any) if all([url.scheme, url.netloc]): # Yes, this was an URL params = parse_qs(url.query) course_nr = params.get('courseNr', [None])[0] return course_nr else: if len(any) == 6: return any match = re.search(r'\w{3}\.\w{3}', any) if match: return match.group(0).replace(".", "") else: return None