def parse_schedule(soup): # There is a single CRN tag associated with every course, so we can use it to find all the info for each course. crn_tags = [ac.parent.findNext('td') for ac in soup.findAll('acronym')] events = [] warnings = [] for crn in crn_tags: # td < tr < table meta_table = crn.parent.parent course_title, course_code, course_section = meta_table.find( 'caption').string.split(' - ') # Week, Type, Time, Days, Where, Date Range, Schedule Type, Instructors times_table = [ list(tr.findAll('td')) for tr in meta_table.findNext('table').findAll('tr')[1:] if meta_table.findNext('table').find('caption').string == "Scheduled Meeting Times" ] for row in times_table: times, day, location, dates, kind, instructor = [ td.string.replace('\xa0', '') if td.string else td.text for td in row ][1:] try: start_time, end_time = (datetime.strptime( time_string, "%I:%M %p") for time_string in times.split(' - ')) start_date, end_date = (datetime.strptime( date_string, "%b %d, %Y") for date_string in dates.split(' - ')) if not start_date or not end_date or not start_time or not end_time: raise ValueError('start or end date/time not defined') except ValueError: warnings += [ 'Course does not have an assigned meeting time: ' + course_title + ' ' + kind ] continue class_dates = weekday.weekday_range(start_date, end_date, day) for date_ in class_dates: datetime_ = datetime(year=date_.year, month=date_.month, day=date_.day) start_datetime = ( datetime_ + timedelta(hours=start_time.hour, minutes=start_time.minute, seconds=start_time.second)).replace( tzinfo=gettz('America/Toronto')) end_datetime = (datetime_ + timedelta(hours=end_time.hour, minutes=end_time.minute, seconds=end_time.second)).replace( tzinfo=gettz('America/Toronto')) event = Event(begin=start_datetime, end=end_datetime) event.name = kind + ': ' + course_title event.summary = kind + ': ' + course_title if 'Synchronous' in location: event.location = 'OT Online' else: event.location = f'Ontario Tech University\n2000 Simcoe St N, Oshawa, ON L1G 0C5\n{location}' event.description = 'CRN: %s\nCourse Code: %s\nSection: %s\nInstructor: %s\n' % ( crn.string, course_code, course_section, instructor.replace(' ', ' ')) events += [event] return events, warnings