#!/bin/env python import argparse import requests from bs4 import BeautifulSoup from datetime import datetime, timedelta, time import icalendar as ical from zoneinfo import ZoneInfo URL = 'https://www.physi.uni-heidelberg.de/Einrichtungen/FP/seminar/seminar.php' SEMINAR_LENGTH = 45 #min def getcal(): page = requests.get(URL) soup = BeautifulSoup(page.content, 'lxml') cal = ical.Calendar() for table in soup.find(id='content').find_all('table')[1:]: try: trs = table.find_all('tr') tutor = trs[0].find_all('th')[1].text.strip() zeit, ort = trs[0].find('td').text.split(',', 1) zeit, ort = zeit.strip(), ort.strip() zeit = time(*map(int, zeit.split(' ')[-1].split(':'))) except Exception as e: print(e) continue for tr in trs[1:]: try: tds = tr.find_all('td') if len(tds) < 2: continue event = ical.Event() datum = datetime.strptime(tds[0].text.strip(), '%d.%m.%y').date() start = datetime.combine(datum, zeit, tzinfo=ZoneInfo('Europe/Berlin')) event.add('dtstart', start) end = start+timedelta(minutes=SEMINAR_LENGTH) event.add('dtend', end) summary = tds[1].text.strip() if summary in ['', 'noch frei', 'kein Vortrag']: continue if len(tds) > 2: name = tds[2].text.strip() if 'kein Seminar' in name: continue summary += ': '+name summary += ' ({})'.format(tutor) event.add('summary', summary) if len(tds) > 3: description = 'Betreuer/in: {}'.format(tds[3].text.strip()) event.add('description', description) event.add('location', ort) cal.add_component(event) except Exception as e: print(e) continue return cal if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument('-o', '--out', type=str, default='fp-seminare.ics', help='Output path') args = parser.parse_args() cal = getcal() with open(args.out, 'wb') as f: f.write(cal.to_ical())