From 10a9fee54b7be9e1392b46b27d8bcd5aba0d6741 Mon Sep 17 00:00:00 2001 From: Domai Date: Mon, 21 Jul 2025 14:29:18 +0200 Subject: [PATCH 1/4] add python starter template --- vvz/.gitignore | 163 +++++++++++++++++++++++++++++++++++++++++++ vvz/README.md | 48 +++++++++++++ vvz/requirements.txt | 1 + vvz/src/main.py | 39 +++++++++++ 4 files changed, 251 insertions(+) create mode 100644 vvz/.gitignore create mode 100644 vvz/README.md create mode 100644 vvz/requirements.txt create mode 100644 vvz/src/main.py diff --git a/vvz/.gitignore b/vvz/.gitignore new file mode 100644 index 0000000..beb0967 --- /dev/null +++ b/vvz/.gitignore @@ -0,0 +1,163 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + +# Directory used by Appwrite CLI for local development +.appwrite \ No newline at end of file diff --git a/vvz/README.md b/vvz/README.md new file mode 100644 index 0000000..32bb3fc --- /dev/null +++ b/vvz/README.md @@ -0,0 +1,48 @@ +# ⚡ Python Starter Function + +A simple starter function. Edit `src/main.py` to get started and create something awesome! 🚀 + +## 🧰 Usage + +### GET /ping + +- Returns a "Pong" message. + +**Response** + +Sample `200` Response: + +```text +Pong +``` + +### GET, POST, PUT, PATCH, DELETE / + +- Returns a "Learn More" JSON response. + +**Response** + +Sample `200` Response: + +```json +{ + "motto": "Build like a team of hundreds_", + "learn": "https://appwrite.io/docs", + "connect": "https://appwrite.io/discord", + "getInspired": "https://builtwith.appwrite.io" +} +``` + +## ⚙ Configuration + +| Setting | Value | +| ----------------- | --------------------------------- | +| Runtime | Python (3.9) | +| Entrypoint | `src/main.py` | +| Build Commands | `pip install -r requirements.txt` | +| Permissions | `any` | +| Timeout (Seconds) | 15 | + +## 🔒 Environment Variables + +No environment variables required. diff --git a/vvz/requirements.txt b/vvz/requirements.txt new file mode 100644 index 0000000..3217f13 --- /dev/null +++ b/vvz/requirements.txt @@ -0,0 +1 @@ +appwrite diff --git a/vvz/src/main.py b/vvz/src/main.py new file mode 100644 index 0000000..b6c28dd --- /dev/null +++ b/vvz/src/main.py @@ -0,0 +1,39 @@ +from appwrite.client import Client +from appwrite.services.users import Users +from appwrite.exception import AppwriteException +import os + +# This Appwrite function will be executed every time your function is triggered +def main(context): + # You can use the Appwrite SDK to interact with other services + # For this example, we're using the Users service + client = ( + Client() + .set_endpoint(os.environ["APPWRITE_FUNCTION_API_ENDPOINT"]) + .set_project(os.environ["APPWRITE_FUNCTION_PROJECT_ID"]) + .set_key(os.environ["APPWRITE_FUNCTION_API_KEY"]) + ) + users = Users(client) + + try: + response = users.list() + # Log messages and errors to the Appwrite Console + # These logs won't be seen by your end users + context.log("Total users: " + str(response["total"])) + except AppwriteException as err: + context.error("Could not list users: " + repr(err)) + + # The req object contains the request data + if context.req.path == "/ping": + # Use res object to respond with text(), json(), or binary() + # Don't forget to return a response! + return context.res.text("Pong") + + return context.res.json( + { + "motto": "Build like a team of hundreds_", + "learn": "https://appwrite.io/docs", + "connect": "https://appwrite.io/discord", + "getInspired": "https://builtwith.appwrite.io", + } + ) From a5954d7c0131924154aab0fa751cc4127bc7193f Mon Sep 17 00:00:00 2001 From: Tasnim2001 Date: Mon, 6 Oct 2025 12:49:22 +0200 Subject: [PATCH 2/4] Scraper prototype (1) --- courses.json | 1703 ++++++++++++++++++++++++++++++++++++++++++++ vvz/src/scraper.py | 335 +++++++++ 2 files changed, 2038 insertions(+) create mode 100644 courses.json create mode 100644 vvz/src/scraper.py diff --git a/courses.json b/courses.json new file mode 100644 index 0000000..b43fd0c --- /dev/null +++ b/courses.json @@ -0,0 +1,1703 @@ +[ + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > FakultĂ€tsweite Veranstaltungen", + "course_id": "", + "title": "010563", + "lecturers": "Kolloquium: SozietĂ€t: Diskurs Praktisch-Theologischer Forschung", + "type": "Karle, Isolde", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > FakultĂ€tsweite Veranstaltungen", + "course_id": "", + "title": "010560", + "lecturers": "Forschungskolloquium mit Doktorand*innen und Habilitand*innen (Blockveranstaltung)", + "type": "Karle, Isolde", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > FakultĂ€tsweite Veranstaltungen", + "course_id": "", + "title": "010460", + "lecturers": "Forschungskolloquium: Systematisch-theologisches Forschungskolloquium (Blockveranstaltung)", + "type": "Thomas, GĂŒnter", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > FakultĂ€tsweite Veranstaltungen", + "course_id": "", + "title": "010160", + "lecturers": "Kolloquium: Forschungskolloquium Altes Testament (Blockveranstaltung)", + "type": "Krause, Joachim ; BĂŒhrer, Walter", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Sprach- und LektĂŒrekurse", + "course_id": "", + "title": "010035a", + "lecturers": "Tutorium HebrĂ€isch (Dommasch)", + "type": "Schmidtkunz, Petra", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Sprach- und LektĂŒrekurse", + "course_id": "", + "title": "010044b", + "lecturers": "Tutorium Altgriechisch Unterkurs (Lara Gerlach)", + "type": "Reis, Burkhard", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Sprach- und LektĂŒrekurse", + "course_id": "", + "title": "010049a", + "lecturers": "Tutorium Altgriechisch Oberkurs (Miriam Gatawis)", + "type": "Reis, Burkhard", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Sprach- und LektĂŒrekurse", + "course_id": "", + "title": "010049b", + "lecturers": "Tutorium Altgriechisch Oberkurs (Sophia Heinrich)", + "type": "Reis, Burkhard", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Sprach- und LektĂŒrekurse", + "course_id": "", + "title": "010035", + "lecturers": "HebrĂ€isch Sprachkurs", + "type": "Schmidtkunz, Petra", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Sprach- und LektĂŒrekurse", + "course_id": "", + "title": "010040", + "lecturers": "Unterkurs Altgriechisch mit Fortsetzung in den Ferien", + "type": "Reis, Burkhard", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Sprach- und LektĂŒrekurse", + "course_id": "", + "title": "010041", + "lecturers": "Unterkurs Altgriechisch mit Fortsetzung in den Ferien (synchron digital)", + "type": "Penzel, Joachim", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Sprach- und LektĂŒrekurse", + "course_id": "", + "title": "010042", + "lecturers": "LektĂŒre zum Unterkurs Altgriechisch", + "type": "Reis, Burkhard", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Sprach- und LektĂŒrekurse", + "course_id": "", + "title": "010043", + "lecturers": "Ferienkurs zum Unterkurs Altgriechisch", + "type": "Penzel, Joachim", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Sprach- und LektĂŒrekurse", + "course_id": "", + "title": "010045", + "lecturers": "Oberkurs Altgriechisch mit Fortsetzung in den Ferien", + "type": "Reis, Burkhard", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Sprach- und LektĂŒrekurse", + "course_id": "", + "title": "010047", + "lecturers": "LektĂŒre zum Oberkurs Altgriechisch", + "type": "Reis, Burkhard", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Sprach- und LektĂŒrekurse", + "course_id": "", + "title": "010048", + "lecturers": "Ferienkurs zum Oberkurs Altgriechisch", + "type": "Reis, Burkhard", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Sprach- und LektĂŒrekurse", + "course_id": "", + "title": "010044a", + "lecturers": "Tutorium Altgriechisch Unterkurs (Jonas Meinert)", + "type": "Reis, Burkhard", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Sprach- und LektĂŒrekurse", + "course_id": "", + "title": "010133", + "lecturers": "Übung: HebrĂ€ische LektĂŒre: Das Hohelied", + "type": "BĂŒhrer, Walter", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Sprach- und LektĂŒrekurse", + "course_id": "", + "title": "010036", + "lecturers": "Griechische LektĂŒre fĂŒr Fortgeschrittene: Epiktet, Vom Kynismus (Diss. III 22)", + "type": "Reis, Burkhard", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Sprachmodul", + "course_id": "", + "title": "010035", + "lecturers": "HebrĂ€isch Sprachkurs", + "type": "Schmidtkunz, Petra", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Sprachmodul", + "course_id": "", + "title": "010040", + "lecturers": "Unterkurs Altgriechisch mit Fortsetzung in den Ferien", + "type": "Reis, Burkhard", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Sprachmodul", + "course_id": "", + "title": "010041", + "lecturers": "Unterkurs Altgriechisch mit Fortsetzung in den Ferien (synchron digital)", + "type": "Penzel, Joachim", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Sprachmodul", + "course_id": "", + "title": "010045", + "lecturers": "Oberkurs Altgriechisch mit Fortsetzung in den Ferien", + "type": "Reis, Burkhard", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Sprachmodul", + "course_id": "", + "title": "010043", + "lecturers": "Ferienkurs zum Unterkurs Altgriechisch", + "type": "Penzel, Joachim", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Sprachmodul", + "course_id": "", + "title": "010048", + "lecturers": "Ferienkurs zum Oberkurs Altgriechisch", + "type": "Reis, Burkhard", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Sprachmodul", + "course_id": "", + "title": "010035a", + "lecturers": "Tutorium HebrĂ€isch (Dommasch)", + "type": "Schmidtkunz, Petra", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Propaedeuticum", + "course_id": "", + "title": "010124", + "lecturers": "Seminar: Bibelkunde Altes Testament", + "type": "Rehr, Maira", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Propaedeuticum", + "course_id": "", + "title": "010103", + "lecturers": "Vorlesung: EinfĂŒhrung in die Evangelische Theologie (BA 2024 und MagTheol)", + "type": "Schmidtkunz, Petra", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Propaedeuticum", + "course_id": "", + "title": "010015", + "lecturers": "Übung: Wissenschaftliches Arbeiten", + "type": "Rehr, Maira", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Basismodul AT", + "course_id": "", + "title": "010120", + "lecturers": "Proseminar: EinfĂŒhrung in die Exegese des Alten Testaments", + "type": "Krause, Kai", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Basismodul AT", + "course_id": "", + "title": "010102", + "lecturers": "Vorlesung: Amos: Prophet – Buch – Wirkung", + "type": "Krause, Joachim", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Basismodul AT", + "course_id": "", + "title": "010100", + "lecturers": "Vorlesung: EinfĂŒhrung in das Alte Testament", + "type": "BĂŒhrer, Walter", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Basismodul NT", + "course_id": "", + "title": "010201", + "lecturers": "Vorlesung: Das Lukasevangelium", + "type": "von Bendemann, Reinhard", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Basismodul NT", + "course_id": "", + "title": "010220", + "lecturers": "Proseminar Neues Testament", + "type": "Wick, Peter", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Basismodul NT", + "course_id": "", + "title": "010200", + "lecturers": "Vorlesung: EinfĂŒhrung in das Neue Testament", + "type": "Wick, Peter", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Basismodul NT", + "course_id": "", + "title": "010202", + "lecturers": "Vorlesung: Das Neue Testament und die Mysterien", + "type": "Wick, Peter", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Basismodul KG", + "course_id": "", + "title": "010321", + "lecturers": "Proseminar: „Wir sind in die Irre gegangen\" – Kirchen im Nationalsozialismus", + "type": "Markert, Laura", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Basismodul KG", + "course_id": "", + "title": "010302", + "lecturers": "Vorlesung: KG I Kirchen- und Christentumsgeschichte in der Antike", + "type": "Greschat, Katharina", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Basismodul KG", + "course_id": "", + "title": "010303", + "lecturers": "Vorlesung: KG III – Reformation", + "type": "Gause, Ute", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Basismodul ST", + "course_id": "", + "title": "010420", + "lecturers": "Proseminar: Medizinethik am Anfang und am Ende des Lebens", + "type": "Schell, Maximilian", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Basismodul ST", + "course_id": "", + "title": "010400", + "lecturers": "Vorlesung: Das Vaterunser als theologischer Grundtext der Christenheit (asynchron)", + "type": "Thomas, GĂŒnter", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Basismodul ST", + "course_id": "", + "title": "010422", + "lecturers": "Proseminar: Unter dem Schatten des Kirchturms – Ekklesiologie", + "type": "Stoppel, Hendrik", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Basismodul ST", + "course_id": "", + "title": "010427", + "lecturers": "Hauptseminar: Theologische BegrĂŒndungen der Demokratie (Blockveranstaltung synchron/digital)", + "type": "Thomas, GĂŒnter", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Basismodul PT", + "course_id": "", + "title": "010500", + "lecturers": "Vorlesung: Gesellschaft und Religion: EinfĂŒhrung in die Praktische Theologie", + "type": "Peuckmann, Niklas", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Basismodul PT", + "course_id": "", + "title": "010527", + "lecturers": "Homiletisches Proseminar", + "type": "Ebbertz, Johannes", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Gemeindepraktikum", + "course_id": "", + "title": "010520", + "lecturers": "Seminar: Vor- und Nachbereitung des Gemeindepraktikums", + "type": "Eichener, Elis", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Basismodul Religionswissenschaft", + "course_id": "", + "title": "010601", + "lecturers": "Vorlesung: EinfĂŒhrung in die Interkulturelle Theologie", + "type": "Stoppel, Hendrik", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Basismodul Religionswissenschaft", + "course_id": "", + "title": "010622", + "lecturers": "Proseminar: EinfĂŒhrung in das religionswissenschaftliche/interkulturelle Arbeiten", + "type": "Hofmann, Beate", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Basismodul Religionswissenschaft", + "course_id": "", + "title": "210002", + "lecturers": "Ringvorlesung \"EinfĂŒhrung in religiöse Traditionen\"", + "type": "Freudenberg, Maren", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Basismodul Religionswissenschaft", + "course_id": "", + "title": "210003", + "lecturers": "Antike und SpĂ€tantike Religionsgeschichte", + "type": "Pientka-Hinz, Rosel ; Rezania, Kianoosh ; Pons, Jessie", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Basismodul Religionswissenschaft", + "course_id": "", + "title": "210055", + "lecturers": "Altorientalische Religionsgeschichte", + "type": "Pientka-Hinz, Rosel", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Basismodul Religionswissenschaft", + "course_id": "", + "title": "210001", + "lecturers": "EinfĂŒhrung in die Religionswissenschaft", + "type": "Motak, Dominika", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > InterdisziplinĂ€res Basismodul", + "course_id": "", + "title": "010731", + "lecturers": "Seminar: Sounds of Peace - Neue Lieder fĂŒr Frieden und Versöhnung (Block)", + "type": "Ebbertz, Johannes", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Wahlpflichtbereich", + "course_id": "", + "title": "060006", + "lecturers": "Evangelisches und Katholisches Kirchenrecht ***", + "type": "KĂ€mper, Burkhard ; Schilberg, Arno", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Wahlpflichtbereich", + "course_id": "", + "title": "010226", + "lecturers": "Seminar: Das Problem der PseudonymitĂ€t frĂŒhchristlicher Schriften", + "type": "von Bendemann, Reinhard", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Wahlpflichtbereich", + "course_id": "", + "title": "010227", + "lecturers": "Das Johannesevangelium (synchron/Block)", + "type": "Cramer, Malte", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Wahlpflichtbereich", + "course_id": "", + "title": "010232", + "lecturers": "Seminar: Taufe und Abendmahl (Block)", + "type": "Klinkmann, Daniel", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Wahlpflichtbereich", + "course_id": "", + "title": "010228", + "lecturers": "\"Herr, sei mir SĂŒnder gnĂ€dig!\" - Grundfragen neutestamentlicher Hamartiologie", + "type": "von Bendemann, Reinhard", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Wahlpflichtbereich", + "course_id": "", + "title": "010300", + "lecturers": "Vorlesung KG: Augustin", + "type": "Greschat, Katharina", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Wahlpflichtbereich", + "course_id": "", + "title": "010533", + "lecturers": "Seminar: Die Ressourcen der Kirchen (digital/Block)", + "type": "Siegl, Christine", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Wahlpflichtbereich", + "course_id": "", + "title": "010534", + "lecturers": "Vorbereitungsseminar Praxissemester", + "type": "Barz, Stefan", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Wahlpflichtbereich", + "course_id": "", + "title": "010535", + "lecturers": "Seminar: Seelsorge (Block; voraussichtlich Februar/MĂ€rz 2026)", + "type": "Dubiski, Katja", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Wahlpflichtbereich", + "course_id": "", + "title": "010133", + "lecturers": "Übung: HebrĂ€ische LektĂŒre: Das Hohelied", + "type": "BĂŒhrer, Walter", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Wahlpflichtbereich", + "course_id": "", + "title": "010136", + "lecturers": "Übung: Die Biblische ArchĂ€ologie und ihre Bedeutung fĂŒr die exegetisch-historische Erforschung der HebrĂ€ischen Bibel: Ei...", + "type": "Krause, Joachim", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Wahlpflichtbereich", + "course_id": "", + "title": "010036", + "lecturers": "Griechische LektĂŒre fĂŒr Fortgeschrittene: Epiktet, Vom Kynismus (Diss. III 22)", + "type": "Reis, Burkhard", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Wahlpflichtbereich", + "course_id": "", + "title": "010521", + "lecturers": "Proseminar: Religion in der Moderne", + "type": "Well, Jula Elene", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Wahlpflichtbereich", + "course_id": "", + "title": "010523", + "lecturers": "Seminar: „Religiöse Bildung fĂŒr nachhaltige Entwicklung“ (Blockveranstaltung)", + "type": "Leibold, Steffen", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Wahlpflichtbereich", + "course_id": "", + "title": "010003", + "lecturers": "Sprachkurs Biblisches AramĂ€isch", + "type": "Schmidtkunz, Petra", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Wahlpflichtbereich", + "course_id": "", + "title": "010233", + "lecturers": "Seminar NT: Sklaverei im Neuen Testament", + "type": "Gutsch, Tom", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Philosophie", + "course_id": "", + "title": "010426", + "lecturers": "Hauptseminar: Verarbeitungen des Holocaust in jĂŒdischer Religionsphilosophie und Literatur", + "type": "Thomas, GĂŒnter", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Aufbaumodul AT", + "course_id": "", + "title": "010102", + "lecturers": "Vorlesung: Amos: Prophet – Buch – Wirkung", + "type": "Krause, Joachim", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Aufbaumodul AT", + "course_id": "", + "title": "010128", + "lecturers": "Hauptseminar AT: Passa und Mazzot – eine Religionsgeschichte (mit HebrĂ€isch)", + "type": "Krause, Joachim", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Aufbaumodul AT", + "course_id": "", + "title": "010129", + "lecturers": "Hauptseminar: Sexualethische Vorstellungen im Alten Testament", + "type": "BĂŒhrer, Walter", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Aufbaumodul NT", + "course_id": "", + "title": "010201", + "lecturers": "Vorlesung: Das Lukasevangelium", + "type": "von Bendemann, Reinhard", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Aufbaumodul NT", + "course_id": "", + "title": "010229", + "lecturers": "Hauptseminar NT: Der Galaterbrief", + "type": "Wick, Peter", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Aufbaumodul NT", + "course_id": "", + "title": "010228", + "lecturers": "\"Herr, sei mir SĂŒnder gnĂ€dig!\" - Grundfragen neutestamentlicher Hamartiologie", + "type": "von Bendemann, Reinhard", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Aufbaumodul NT", + "course_id": "", + "title": "010202", + "lecturers": "Vorlesung: Das Neue Testament und die Mysterien", + "type": "Wick, Peter", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Aufbaumodul NT", + "course_id": "", + "title": "010230", + "lecturers": "Hauptseminar: Paulus und die Juden. Die Juden und Paulus", + "type": "Klinkmann, Daniel", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Aufbaumodul KG", + "course_id": "", + "title": "010302", + "lecturers": "Vorlesung: KG I Kirchen- und Christentumsgeschichte in der Antike", + "type": "Greschat, Katharina", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Aufbaumodul KG", + "course_id": "", + "title": "010303", + "lecturers": "Vorlesung: KG III – Reformation", + "type": "Gause, Ute", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Aufbaumodul KG", + "course_id": "", + "title": "010300", + "lecturers": "Vorlesung KG: Augustin", + "type": "Greschat, Katharina", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Aufbaumodul KG", + "course_id": "", + "title": "010328", + "lecturers": "Übung zur Vorlesung: Kirchen- und Christentumsgeschichte in der Antike (freiwillige ErgĂ€nzung zur Vorlesung)", + "type": "Greschat, Katharina", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Aufbaumodul KG", + "course_id": "", + "title": "020043", + "lecturers": "\"Geschichte einer wilden Handlung\" (G. Schwerhoff)? Die Bauernkriege 1524-26. Evangelische und katholische Perspektiven", + "type": "Bock, Florian ; Gause, Ute", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Aufbaumodul ST (Dogmatik und Ethik)", + "course_id": "", + "title": "010402", + "lecturers": "Vorlesung: Hamartiologie. Die christliche Lehre von der SĂŒnde", + "type": "Thomas, GĂŒnter", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Aufbaumodul ST (Dogmatik und Ethik)", + "course_id": "", + "title": "010424", + "lecturers": "Hauptseminar: Paul Tillich: Der Mut zum Sein (Blockseminar)", + "type": "Berner, Knut", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Aufbaumodul ST (Dogmatik und Ethik)", + "course_id": "", + "title": "010425", + "lecturers": "Hauptseminar: Was bleibt (uns)? – PhĂ€nomene der Überdauerung in der Krise", + "type": "Stoppel, Hendrik", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Aufbaumodul ST (Dogmatik und Ethik)", + "course_id": "", + "title": "010426", + "lecturers": "Hauptseminar: Verarbeitungen des Holocaust in jĂŒdischer Religionsphilosophie und Literatur", + "type": "Thomas, GĂŒnter", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Aufbaumodul ST (Dogmatik und Ethik)", + "course_id": "", + "title": "010427", + "lecturers": "Hauptseminar: Theologische BegrĂŒndungen der Demokratie (Blockveranstaltung synchron/digital)", + "type": "Thomas, GĂŒnter", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Aufbaumodul PT", + "course_id": "", + "title": "010500", + "lecturers": "Vorlesung: Gesellschaft und Religion: EinfĂŒhrung in die Praktische Theologie", + "type": "Peuckmann, Niklas", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Aufbaumodul PT", + "course_id": "", + "title": "010524", + "lecturers": "Seminar Fachdidaktik: Diakonie als Thema des RU", + "type": "Waltemathe, Michael", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Aufbaumodul Religionswissenschaft", + "course_id": "", + "title": "010621", + "lecturers": "Seminar: Ich bin klein, mein Herz ist rein – Reinheitsvorstellungen in Religion und Politik", + "type": "Stoppel, Hendrik", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Aufbaumodul Religionswissenschaft", + "course_id": "", + "title": "210003", + "lecturers": "Antike und SpĂ€tantike Religionsgeschichte", + "type": "Pientka-Hinz, Rosel ; Rezania, Kianoosh ; Pons, Jessie", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Aufbaumodul Religionswissenschaft", + "course_id": "", + "title": "210055", + "lecturers": "Altorientalische Religionsgeschichte", + "type": "Pientka-Hinz, Rosel", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Aufbaumodul Religionswissenschaft", + "course_id": "", + "title": "210023", + "lecturers": "Das Weltparlament der Religionen (1893)", + "type": "Di Giacinto, Licia", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > InterdisziplinĂ€res Aufbaumodul", + "course_id": "", + "title": "010525", + "lecturers": "Seminar FD/FW: Gesellschaft und Technik als Thema des RU (Blockveranstaltung mit Exkursion nach Karlsruhe)", + "type": "Waltemathe, Michael", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > InterdisziplinĂ€res Aufbaumodul", + "course_id": "", + "title": "010731", + "lecturers": "Seminar: Sounds of Peace - Neue Lieder fĂŒr Frieden und Versöhnung (Block)", + "type": "Ebbertz, Johannes", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Integrationsmodul NT", + "course_id": "", + "title": "010231", + "lecturers": "Rep NT: Examensrepetitorium", + "type": "von Bendemann, Reinhard", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Integrationsmodul ST", + "course_id": "", + "title": "010430", + "lecturers": "Repetitorium: Systematische Theologie (Dogmatik & Ethik)", + "type": "Schell, Maximilian", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Integrationsmodul PT", + "course_id": "", + "title": "010531", + "lecturers": "Repetitorium Praktische Theologie", + "type": "Eichener, Elis", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Orientierungsmodul (nur PO 2024)", + "course_id": "", + "title": "010103", + "lecturers": "Vorlesung: EinfĂŒhrung in die Evangelische Theologie (BA 2024 und MagTheol)", + "type": "Schmidtkunz, Petra", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Orientierungsmodul (nur PO 2024)", + "course_id": "", + "title": "010015", + "lecturers": "Übung: Wissenschaftliches Arbeiten", + "type": "Rehr, Maira", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Orientierungsmodul (nur PO 2024)", + "course_id": "", + "title": "010150", + "lecturers": "Übung zur Bibelkunde (AT und NT) [nur BA 2024]", + "type": "Rehr, Maira", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Altes Testament und Neues Testament/ Bibelwissenschaften", + "course_id": "", + "title": "010100", + "lecturers": "Vorlesung: EinfĂŒhrung in das Alte Testament", + "type": "BĂŒhrer, Walter", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Altes Testament und Neues Testament/ Bibelwissenschaften", + "course_id": "", + "title": "010126", + "lecturers": "Seminar AT: Schöpfung als Thema der HebrĂ€ischen Bibel", + "type": "Krause, Kai", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Altes Testament und Neues Testament/ Bibelwissenschaften", + "course_id": "", + "title": "010135", + "lecturers": "Seminar: Theological Uncertainty and the Book of Qoheleth (PrĂ€senz/digital)", + "type": "Glanz, Julia", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Altes Testament und Neues Testament/ Bibelwissenschaften", + "course_id": "", + "title": "010226", + "lecturers": "Seminar: Das Problem der PseudonymitĂ€t frĂŒhchristlicher Schriften", + "type": "von Bendemann, Reinhard", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Altes Testament und Neues Testament/ Bibelwissenschaften", + "course_id": "", + "title": "010227", + "lecturers": "Das Johannesevangelium (synchron/Block)", + "type": "Cramer, Malte", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Altes Testament und Neues Testament/ Bibelwissenschaften", + "course_id": "", + "title": "010200", + "lecturers": "Vorlesung: EinfĂŒhrung in das Neue Testament", + "type": "Wick, Peter", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Altes Testament und Neues Testament/ Bibelwissenschaften", + "course_id": "", + "title": "010232", + "lecturers": "Seminar: Taufe und Abendmahl (Block)", + "type": "Klinkmann, Daniel", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Altes Testament und Neues Testament/ Bibelwissenschaften", + "course_id": "", + "title": "010220", + "lecturers": "Proseminar Neues Testament", + "type": "Wick, Peter", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Altes Testament und Neues Testament/ Bibelwissenschaften", + "course_id": "", + "title": "010137", + "lecturers": "Seminar AT: Kreativ und subversiv: Aktive Frauenfiguren im Alten Testament", + "type": "Marschall, Anja", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Altes Testament und Neues Testament/ Bibelwissenschaften", + "course_id": "", + "title": "010233", + "lecturers": "Seminar NT: Sklaverei im Neuen Testament", + "type": "Gutsch, Tom", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Kirchengeschichte", + "course_id": "", + "title": "010321", + "lecturers": "Proseminar: „Wir sind in die Irre gegangen\" – Kirchen im Nationalsozialismus", + "type": "Markert, Laura", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Kirchengeschichte", + "course_id": "", + "title": "010301", + "lecturers": "Vorlesung: Alte Kirche bis Reformationszeit", + "type": "Greschat, Katharina", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Kirchengeschichte", + "course_id": "", + "title": "010322", + "lecturers": "Seminar KG: Christliche MĂ€rtyrer*innen und Apologeten – Action-Heroes in der Arena und ihre SchreibtischtĂ€ter", + "type": "Scheel, Tristan", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Kirchengeschichte", + "course_id": "", + "title": "010323", + "lecturers": "Seminar: \"Wie hĂ€ltst du’s mit der Religion?“ – Alltagstheologie der Reformation", + "type": "Markert, Laura", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Systematische Theologie", + "course_id": "", + "title": "010420", + "lecturers": "Proseminar: Medizinethik am Anfang und am Ende des Lebens", + "type": "Schell, Maximilian", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Systematische Theologie", + "course_id": "", + "title": "010400", + "lecturers": "Vorlesung: Das Vaterunser als theologischer Grundtext der Christenheit (asynchron)", + "type": "Thomas, GĂŒnter", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Systematische Theologie", + "course_id": "", + "title": "010422", + "lecturers": "Proseminar: Unter dem Schatten des Kirchturms – Ekklesiologie", + "type": "Stoppel, Hendrik", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Systematische Theologie", + "course_id": "", + "title": "010427", + "lecturers": "Hauptseminar: Theologische BegrĂŒndungen der Demokratie (Blockveranstaltung synchron/digital)", + "type": "Thomas, GĂŒnter", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Systematische Theologie", + "course_id": "", + "title": "010404", + "lecturers": "VL: EinfĂŒhrung in die Evangelische Theologie (elearning - nur fĂŒr BA-Studierende der PO 2016/2019)", + "type": "Stoppel, Hendrik", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Praktische Theologie", + "course_id": "", + "title": "010521", + "lecturers": "Proseminar: Religion in der Moderne", + "type": "Well, Jula Elene", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Religionswissenschaft/ Interkulturelle Theologie (nur PO 2024)", + "course_id": "", + "title": "010601", + "lecturers": "Vorlesung: EinfĂŒhrung in die Interkulturelle Theologie", + "type": "Stoppel, Hendrik", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Religionswissenschaft/ Interkulturelle Theologie (nur PO 2024)", + "course_id": "", + "title": "010622", + "lecturers": "Proseminar: EinfĂŒhrung in das religionswissenschaftliche/interkulturelle Arbeiten", + "type": "Hofmann, Beate", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Religionswissenschaft/ Interkulturelle Theologie (nur PO 2024)", + "course_id": "", + "title": "210002", + "lecturers": "Ringvorlesung \"EinfĂŒhrung in religiöse Traditionen\"", + "type": "Freudenberg, Maren", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Religionswissenschaft/ Interkulturelle Theologie (nur PO 2024)", + "course_id": "", + "title": "210003", + "lecturers": "Antike und SpĂ€tantike Religionsgeschichte", + "type": "Pientka-Hinz, Rosel ; Rezania, Kianoosh ; Pons, Jessie", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Religionswissenschaft/ Interkulturelle Theologie (nur PO 2024)", + "course_id": "", + "title": "210055", + "lecturers": "Altorientalische Religionsgeschichte", + "type": "Pientka-Hinz, Rosel", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Religionswissenschaft/ Interkulturelle Theologie (nur PO 2024)", + "course_id": "", + "title": "210001", + "lecturers": "EinfĂŒhrung in die Religionswissenschaft", + "type": "Motak, Dominika", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Religionswissenschaft/ Interkulturelle Theologie (nur PO 2024)", + "course_id": "", + "title": "210023", + "lecturers": "Das Weltparlament der Religionen (1893)", + "type": "Di Giacinto, Licia", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > InterdisziplinĂ€res Modul (nur PO 2016 und PO 2019)", + "course_id": "", + "title": "010731", + "lecturers": "Seminar: Sounds of Peace - Neue Lieder fĂŒr Frieden und Versöhnung (Block)", + "type": "Ebbertz, Johannes", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Wahlpflichtbereich", + "course_id": "", + "title": "060006", + "lecturers": "Evangelisches und Katholisches Kirchenrecht ***", + "type": "KĂ€mper, Burkhard ; Schilberg, Arno", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Wahlpflichtbereich", + "course_id": "", + "title": "010136", + "lecturers": "Übung: Die Biblische ArchĂ€ologie und ihre Bedeutung fĂŒr die exegetisch-historische Erforschung der HebrĂ€ischen Bibel: Ei...", + "type": "Krause, Joachim", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Wahlpflichtbereich", + "course_id": "", + "title": "010202", + "lecturers": "Vorlesung: Das Neue Testament und die Mysterien", + "type": "Wick, Peter", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Wahlpflichtbereich", + "course_id": "", + "title": "010300", + "lecturers": "Vorlesung KG: Augustin", + "type": "Greschat, Katharina", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Wahlpflichtbereich", + "course_id": "", + "title": "010533", + "lecturers": "Seminar: Die Ressourcen der Kirchen (digital/Block)", + "type": "Siegl, Christine", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Wahlpflichtbereich", + "course_id": "", + "title": "010535", + "lecturers": "Seminar: Seelsorge (Block; voraussichtlich Februar/MĂ€rz 2026)", + "type": "Dubiski, Katja", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Wahlpflichtbereich", + "course_id": "", + "title": "010731", + "lecturers": "Seminar: Sounds of Peace - Neue Lieder fĂŒr Frieden und Versöhnung (Block)", + "type": "Ebbertz, Johannes", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Wahlpflichtbereich", + "course_id": "", + "title": "010133", + "lecturers": "Übung: HebrĂ€ische LektĂŒre: Das Hohelied", + "type": "BĂŒhrer, Walter", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Wahlpflichtbereich", + "course_id": "", + "title": "010036", + "lecturers": "Griechische LektĂŒre fĂŒr Fortgeschrittene: Epiktet, Vom Kynismus (Diss. III 22)", + "type": "Reis, Burkhard", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Wahlpflichtbereich", + "course_id": "", + "title": "010035a", + "lecturers": "Tutorium HebrĂ€isch (Dommasch)", + "type": "Schmidtkunz, Petra", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Wahlpflichtbereich", + "course_id": "", + "title": "010527", + "lecturers": "Homiletisches Proseminar", + "type": "Ebbertz, Johannes", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Wahlpflichtbereich", + "course_id": "", + "title": "010003", + "lecturers": "Sprachkurs Biblisches AramĂ€isch", + "type": "Schmidtkunz, Petra", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Modul MA: Altes Testament", + "course_id": "", + "title": "010102", + "lecturers": "Vorlesung: Amos: Prophet – Buch – Wirkung", + "type": "Krause, Joachim", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Modul MA: Altes Testament", + "course_id": "", + "title": "010128", + "lecturers": "Hauptseminar AT: Passa und Mazzot – eine Religionsgeschichte (mit HebrĂ€isch)", + "type": "Krause, Joachim", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Modul MB: Neues Testament", + "course_id": "", + "title": "010129", + "lecturers": "Hauptseminar: Sexualethische Vorstellungen im Alten Testament", + "type": "BĂŒhrer, Walter", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Modul MB: Neues Testament", + "course_id": "", + "title": "010202", + "lecturers": "Vorlesung: Das Neue Testament und die Mysterien", + "type": "Wick, Peter", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Modul MB: Neues Testament", + "course_id": "", + "title": "010201", + "lecturers": "Vorlesung: Das Lukasevangelium", + "type": "von Bendemann, Reinhard", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Modul MB: Neues Testament", + "course_id": "", + "title": "010230", + "lecturers": "Hauptseminar: Paulus und die Juden. Die Juden und Paulus", + "type": "Klinkmann, Daniel", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Modul MB: Neues Testament", + "course_id": "", + "title": "010228", + "lecturers": "\"Herr, sei mir SĂŒnder gnĂ€dig!\" - Grundfragen neutestamentlicher Hamartiologie", + "type": "von Bendemann, Reinhard", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Modul MB: Neues Testament", + "course_id": "", + "title": "010229", + "lecturers": "Hauptseminar NT: Der Galaterbrief", + "type": "Wick, Peter", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Modul MC: Kirchengeschichte", + "course_id": "", + "title": "010303", + "lecturers": "Vorlesung: KG III – Reformation", + "type": "Gause, Ute", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Modul MC: Kirchengeschichte", + "course_id": "", + "title": "010302", + "lecturers": "Vorlesung: KG I Kirchen- und Christentumsgeschichte in der Antike", + "type": "Greschat, Katharina", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Modul MC: Kirchengeschichte", + "course_id": "", + "title": "010328", + "lecturers": "Übung zur Vorlesung: Kirchen- und Christentumsgeschichte in der Antike (freiwillige ErgĂ€nzung zur Vorlesung)", + "type": "Greschat, Katharina", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Modul MC: Kirchengeschichte", + "course_id": "", + "title": "020043", + "lecturers": "\"Geschichte einer wilden Handlung\" (G. Schwerhoff)? Die Bauernkriege 1524-26. Evangelische und katholische Perspektiven", + "type": "Bock, Florian ; Gause, Ute", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Modul MD: Dogmatik", + "course_id": "", + "title": "010402", + "lecturers": "Vorlesung: Hamartiologie. Die christliche Lehre von der SĂŒnde", + "type": "Thomas, GĂŒnter", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Modul MD: Dogmatik", + "course_id": "", + "title": "010424", + "lecturers": "Hauptseminar: Paul Tillich: Der Mut zum Sein (Blockseminar)", + "type": "Berner, Knut", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Modul MD: Dogmatik", + "course_id": "", + "title": "010425", + "lecturers": "Hauptseminar: Was bleibt (uns)? – PhĂ€nomene der Überdauerung in der Krise", + "type": "Stoppel, Hendrik", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Modul MD: Dogmatik", + "course_id": "", + "title": "010426", + "lecturers": "Hauptseminar: Verarbeitungen des Holocaust in jĂŒdischer Religionsphilosophie und Literatur", + "type": "Thomas, GĂŒnter", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Modul ME: Ethik", + "course_id": "", + "title": "010402", + "lecturers": "Vorlesung: Hamartiologie. Die christliche Lehre von der SĂŒnde", + "type": "Thomas, GĂŒnter", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Modul ME: Ethik", + "course_id": "", + "title": "010426", + "lecturers": "Hauptseminar: Verarbeitungen des Holocaust in jĂŒdischer Religionsphilosophie und Literatur", + "type": "Thomas, GĂŒnter", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Modul ME: Ethik", + "course_id": "", + "title": "010427", + "lecturers": "Hauptseminar: Theologische BegrĂŒndungen der Demokratie (Blockveranstaltung synchron/digital)", + "type": "Thomas, GĂŒnter", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Modul MF: Praktische Theologie", + "course_id": "", + "title": "010501", + "lecturers": "Vorlesung: EinfĂŒhrung in die ReligionspĂ€dagogik", + "type": "Waltemathe, Michael", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Modul MF: Praktische Theologie", + "course_id": "", + "title": "010500", + "lecturers": "Vorlesung: Gesellschaft und Religion: EinfĂŒhrung in die Praktische Theologie", + "type": "Peuckmann, Niklas", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Modul MF: Praktische Theologie", + "course_id": "", + "title": "010533", + "lecturers": "Seminar: Die Ressourcen der Kirchen (digital/Block)", + "type": "Siegl, Christine", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Modul MF: Praktische Theologie", + "course_id": "", + "title": "010534", + "lecturers": "Vorbereitungsseminar Praxissemester", + "type": "Barz, Stefan", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Modul MF: Praktische Theologie", + "course_id": "", + "title": "010535", + "lecturers": "Seminar: Seelsorge (Block; voraussichtlich Februar/MĂ€rz 2026)", + "type": "Dubiski, Katja", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Modul MF: Praktische Theologie", + "course_id": "", + "title": "010731", + "lecturers": "Seminar: Sounds of Peace - Neue Lieder fĂŒr Frieden und Versöhnung (Block)", + "type": "Ebbertz, Johannes", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Modul MF: Praktische Theologie", + "course_id": "", + "title": "010523", + "lecturers": "Seminar: „Religiöse Bildung fĂŒr nachhaltige Entwicklung“ (Blockveranstaltung)", + "type": "Leibold, Steffen", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Modul MG: Religionswissenschaft", + "course_id": "", + "title": "010601", + "lecturers": "Vorlesung: EinfĂŒhrung in die Interkulturelle Theologie", + "type": "Stoppel, Hendrik", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Modul MG: Religionswissenschaft", + "course_id": "", + "title": "010621", + "lecturers": "Seminar: Ich bin klein, mein Herz ist rein – Reinheitsvorstellungen in Religion und Politik", + "type": "Stoppel, Hendrik", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Modul MG: Religionswissenschaft", + "course_id": "", + "title": "210002", + "lecturers": "Ringvorlesung \"EinfĂŒhrung in religiöse Traditionen\"", + "type": "Freudenberg, Maren", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Modul MH: Philosophie", + "course_id": "", + "title": "010426", + "lecturers": "Hauptseminar: Verarbeitungen des Holocaust in jĂŒdischer Religionsphilosophie und Literatur", + "type": "Thomas, GĂŒnter", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Modul MBW: Bibelwissenschaften", + "course_id": "", + "title": "010102", + "lecturers": "Vorlesung: Amos: Prophet – Buch – Wirkung", + "type": "Krause, Joachim", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Modul MBW: Bibelwissenschaften", + "course_id": "", + "title": "010128", + "lecturers": "Hauptseminar AT: Passa und Mazzot – eine Religionsgeschichte (mit HebrĂ€isch)", + "type": "Krause, Joachim", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Modul MBW: Bibelwissenschaften", + "course_id": "", + "title": "010129", + "lecturers": "Hauptseminar: Sexualethische Vorstellungen im Alten Testament", + "type": "BĂŒhrer, Walter", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Modul MBW: Bibelwissenschaften", + "course_id": "", + "title": "010202", + "lecturers": "Vorlesung: Das Neue Testament und die Mysterien", + "type": "Wick, Peter", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Modul MBW: Bibelwissenschaften", + "course_id": "", + "title": "010201", + "lecturers": "Vorlesung: Das Lukasevangelium", + "type": "von Bendemann, Reinhard", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Modul MBW: Bibelwissenschaften", + "course_id": "", + "title": "010229", + "lecturers": "Hauptseminar NT: Der Galaterbrief", + "type": "Wick, Peter", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Modul MBW: Bibelwissenschaften", + "course_id": "", + "title": "010230", + "lecturers": "Hauptseminar: Paulus und die Juden. Die Juden und Paulus", + "type": "Klinkmann, Daniel", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Modul MBW: Bibelwissenschaften", + "course_id": "", + "title": "010228", + "lecturers": "\"Herr, sei mir SĂŒnder gnĂ€dig!\" - Grundfragen neutestamentlicher Hamartiologie", + "type": "von Bendemann, Reinhard", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Modul MKG: Kirchengeschichte", + "course_id": "", + "title": "010303", + "lecturers": "Vorlesung: KG III – Reformation", + "type": "Gause, Ute", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Modul MKG: Kirchengeschichte", + "course_id": "", + "title": "010302", + "lecturers": "Vorlesung: KG I Kirchen- und Christentumsgeschichte in der Antike", + "type": "Greschat, Katharina", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Modul MKG: Kirchengeschichte", + "course_id": "", + "title": "010328", + "lecturers": "Übung zur Vorlesung: Kirchen- und Christentumsgeschichte in der Antike (freiwillige ErgĂ€nzung zur Vorlesung)", + "type": "Greschat, Katharina", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Modul MKG: Kirchengeschichte", + "course_id": "", + "title": "020043", + "lecturers": "\"Geschichte einer wilden Handlung\" (G. Schwerhoff)? Die Bauernkriege 1524-26. Evangelische und katholische Perspektiven", + "type": "Bock, Florian ; Gause, Ute", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Modul MST: Systematische Theologie", + "course_id": "", + "title": "010402", + "lecturers": "Vorlesung: Hamartiologie. Die christliche Lehre von der SĂŒnde", + "type": "Thomas, GĂŒnter", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Modul MST: Systematische Theologie", + "course_id": "", + "title": "010424", + "lecturers": "Hauptseminar: Paul Tillich: Der Mut zum Sein (Blockseminar)", + "type": "Berner, Knut", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Modul MST: Systematische Theologie", + "course_id": "", + "title": "010425", + "lecturers": "Hauptseminar: Was bleibt (uns)? – PhĂ€nomene der Überdauerung in der Krise", + "type": "Stoppel, Hendrik", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Modul MST: Systematische Theologie", + "course_id": "", + "title": "010426", + "lecturers": "Hauptseminar: Verarbeitungen des Holocaust in jĂŒdischer Religionsphilosophie und Literatur", + "type": "Thomas, GĂŒnter", + "detail_url": null, + "schedule": [] + }, + { + "module_path": "I. Evangelisch-Theologische FakultĂ€t > Modul MST: Systematische Theologie", + "course_id": "", + "title": "010427", + "lecturers": "Hauptseminar: Theologische BegrĂŒndungen der Demokratie (Blockveranstaltung synchron/digital)", + "type": "Thomas, GĂŒnter", + "detail_url": null, + "schedule": [] + } +] \ No newline at end of file diff --git a/vvz/src/scraper.py b/vvz/src/scraper.py new file mode 100644 index 0000000..3639085 --- /dev/null +++ b/vvz/src/scraper.py @@ -0,0 +1,335 @@ +import requests +from bs4 import BeautifulSoup +from urllib.parse import urljoin +from selenium import webdriver +from selenium.webdriver.chrome.options import Options +import time , re , json + +def get_rendered_html(url, wait=3): + options = Options() + options.add_argument("--headless=new") + options.add_argument("--disable-gpu") + options.add_argument("--no-sandbox") + options.add_argument("--disable-dev-shm-usage") + + driver = webdriver.Chrome(options=options) + try: + driver.get(url) + time.sleep(wait) + html = driver.page_source + finally: + driver.quit() + return html + + +start_url = "https://vvz.ruhr-uni-bochum.de/campus/all/fields.asp?group=Vorlesungsverzeichnis&lang=de" + +# FakultĂ€ten erkennen +roman_re = re.compile(r'^([IVXLCDM]+)\.') +def is_faculty(text: str) -> bool: + return bool(roman_re.match(text)) and "FakultĂ€t" in text + +def roman_order(name: str) -> int: + order = ["I.","II.","III.","IV.","V.","VI.","VII.","VIII.","IX.","X.", + "XI.","XII.","XIII.","XIV.","XV.","XVI.","XVII.","XVIII.","XIX.","XX.","XXI."] + m = roman_re.match(name.strip()) + token = (m.group(1) + '.') if m else 'ZZZ.' + return order.index(token) if token in order else 999 + + +def clean_lecturers(td): + # Zerlegt den Text an ZeilenumbrĂŒchen (z.B.
), entfernt leere EintrĂ€ge + if not td: + return "" + parts = [p.strip() for p in td.stripped_strings if p.strip()] + return " ; ".join(parts) + + + + +def list_courses(eventlist_url: str, module_title: str | None = None): + #print(f"[DEBUG] RENDER mit Selenium: {eventlist_url}") + html = get_rendered_html(eventlist_url) + #print(f"[DEBUG] LĂ€nge HTML: {len(html)}") + soup = BeautifulSoup(html, "html.parser") + + + + tables = soup.find_all("tbody", class_="tablecontent") + if not tables: + return [] + + courses = [] + + # ALLE Tabellen der Seite durchlaufen + for tbody in tables: + number_cells = tbody.find_all("td", id=re.compile("cas-table_EVENTLIST_COURSENUMBER_\\d+")) + for num_cell in number_cells: + tr = num_cell.find_parent("tr") + if not tr: + continue + + # Index aus ID holen + match = re.search(r"_(\d+)$", num_cell.get("id", "")) + if not match: + continue + idx = match.group(1) + + # Daten wie gewohnt auslesen + course_id = num_cell.get_text(" ", strip=True) + link_tag = num_cell.find("a") + detail_url = urljoin(eventlist_url, link_tag["href"]) if link_tag else None + + title_td = tr.find("td", id=f"cas-table_EVENTLIST_TITLE_{idx}") + lecturer_td = tr.find("td", id=f"cas-table_EVENTLIST_LECTURER_{idx}") + type_td = tr.find("td", id=f"cas-table_EVENTLIST_SWS_{idx}") + + title = title_td.get_text(" ", strip=True) if title_td else "" + lecturers = clean_lecturers(lecturer_td) + type_ = type_td.get_text(" ", strip=True) if type_td else "" + + details = scrape_course_details(detail_url) if detail_url else {"basisdaten": {}, "termine": []} + + courses.append({ + "module": module_title, + "course_id": course_id, + "title": title, + "lecturers": lecturers, + "type": type_, + "details_url": detail_url, + "basisdaten": details.get("basisdaten"), + "termine": details.get("termine") + }) + + return courses + + + + +def scrape_course_details(url): + try: + r = requests.get(url, timeout=10) # statt 30 + r.raise_for_status() + except Exception as e: + print(f"[WARN] Detailseite konnte nicht geladen werden: {url} ({e})") + return {"basisdaten": {}, "termine": []} + + +visited = set() + +""" def scrape_items(url, path=None): + if path is None: + path = [] + + if url in visited: + return [] + visited.add(url) + + try: + html = get_rendered_html(url) + except Exception as e: + print(f"[WARN] Fehler bei {url}: {e}") + return [] + + soup = BeautifulSoup(html, "html.parser") + + # === Fall 1: Kursliste (eventlist.asp) === + if "eventlist.asp" in url: + module_name = " > ".join(path) + print(f"\n Modul: {module_name}") + courses = list_courses(url, module_title=module_name) + for c in courses: + print(f" | {c['course_id']} | {c['title']} | {c['lecturers']} | {c['type']}") + if c.get("termine"): + for t in c["termine"]: + wochentag = t.get("wochentag", "") + start = t.get("start", "") + ende = t.get("ende", "") + raum = t.get("raum", "") + datum = t.get("datum", "") + print(f" {wochentag} {start}–{ende} @ {raum} ({datum})") + return courses + + # === Fall 2: Untermodul-Liste (subfields.asp oder fields.asp) === + tbody = soup.find("tbody", class_="tablecontent") + if not tbody: + return [] + + results = [] + for a in tbody.find_all("a"): + text = a.get_text(strip=True) + href = a.get("href") or "" + if not text or not href: + continue + if href.startswith("#") or href.lower().startswith("javascript:"): + continue + + full_url = urljoin(url, href) + + # Rekursion → gehe tiefer + results.extend(scrape_items(full_url, path + [text])) + time.sleep(0.2) + + return results """ + +def scrape_items(url, path=None): + if path is None: + path = [] + + if url in visited: + return [] + visited.add(url) + + try: + html = get_rendered_html(url) + except Exception as e: + print(f"[WARN] Fehler bei {url}: {e}") + return [] + + soup = BeautifulSoup(html, "html.parser") + + # === Fall 1: Kursliste (eventlist.asp) === + if "eventlist.asp" in url: + module_name = " > ".join(path) + if len(path)==1: + return [] + print(f"\n Modul: {module_name}") + courses = list_courses(url, module_title=module_name) + + for c in courses: + print(f" | {c['course_id']} | {c['title']} | {c['lecturers']} | {c['type']}") + if c.get("termine"): + for t in c["termine"]: + wochentag = t.get("wochentag", "") + start = t.get("start", "") + ende = t.get("ende", "") + raum = t.get("raum", "") + datum = t.get("datum", "") + print(f" {wochentag} {start}–{ende} @ {raum} ({datum})") + return courses + + # === Fall 2: Untermodul-Liste (subfields.asp oder fields.asp) === + tbody = soup.find("tbody", class_="tablecontent") + if not tbody: + return [] + + results = [] + for a in tbody.find_all("a"): + text = a.get_text(strip=True) + href = a.get("href") or "" + if not text or not href: + continue + if href.startswith("#") or href.lower().startswith("javascript:"): + continue + + full_url = urljoin(url, href) + + # doppelte Namenswiederholung verhindern + if path and path[-1] == text: + new_path = path # nicht nochmal anhĂ€ngen + else: + new_path = path + [text] + + # Rekursion → gehe tiefer + results.extend(scrape_items(full_url, new_path)) + time.sleep(0.2) + + return results + + + + +def scrape_course_details(url): + r = requests.get(url, timeout=30) + r.raise_for_status() + soup = BeautifulSoup(r.text, "html.parser") + + # --- Basisdaten --- + base_data = {} + for row in soup.select("div.templatecomponent.collapsible div.cas-info-row"): + label = row.find("div", class_="cas-info-label") + value = row.find("div", class_="cas-info-value") + if label and value: + key = label.get_text(strip=True).replace(":", "") + val = value.get_text(" ", strip=True) + base_data[key] = val + + # Termine + termine = [] + table = soup.find("table", id="appointmentlist") + if table: + # Oberste Terminzeile mit Wochentag, Uhrzeit, Raum + header_td = table.select_one("tbody.tablecontent tr td") + if header_td: + header_text = header_td.get_text(" ", strip=True) + + m = re.match(r"^([A-Za-z]+),\s*([\d:]+)\s*-\s*([\d:]+),\s*(.+)$", header_text) + if m: + wochentag = m.group(1) + startzeit = m.group(2) + endzeit = m.group(3) + raum = m.group(4) + else: + wochentag = startzeit = endzeit = raum = "" + + # Einzeltermine → nach dem Header kommen weitere + date_rows = table.select("tbody.tablecontent tr")[1:] # ab 2. Zeile + for row in date_rows: + date_text = row.get_text(" ", strip=True) + if not date_text: + continue + termine.append({ + "datum": date_text, + "wochentag": wochentag, + "start": startzeit, + "ende": endzeit, + "raum": raum + }) + + return { + "basisdaten": base_data, + "termine": termine + } + + + + +# Hauptlauf +r = requests.get(start_url, timeout=30) +r.raise_for_status() +soup = BeautifulSoup(r.text, "html.parser") + +faculties = [] +seen = set() +for a in soup.find_all("a"): + text = a.get_text(strip=True) + href = a.get("href") + if not text or not href or not is_faculty(text): + continue + full_url = urljoin(start_url, href) + key = (text, full_url) + if key not in seen: + seen.add(key) + faculties.append(key) + +faculties.sort(key=lambda x: roman_order(x[0])) +faculties = faculties[:1] # zum Testen nur die erste FakultĂ€t +all_courses = [] + +for fac_name, fac_url in faculties: + print(f"\n====== {fac_name} ======") + courses = scrape_items(fac_url, [fac_name]) + all_courses.extend(courses) + + +# hier nur zum testen der ersten Ebene also nur name der FakulitĂ€ten mit dennen Links +"""print("\n====== FakultĂ€ten (Testlauf) ======") +for i, (name, url) in enumerate(faculties): + print(f"{i+1:02d}. {name} → {url}")""" + +# JSON-Ausgabe +print(json.dumps(all_courses, indent=2, ensure_ascii=False)) + + + + From 64f30006ef59b4c165e14605983550fc77292de3 Mon Sep 17 00:00:00 2001 From: Tasnim2001 Date: Tue, 2 Dec 2025 13:21:40 +0100 Subject: [PATCH 3/4] scraping improved --- progress.txt | 2 + progress_I.txt | 86 ++++ progress_II.txt | 74 +++ progress_IX.txt | 348 ++++++++++++++ progress_VI.txt | 230 ++++++++++ progress_VII.txt | 191 ++++++++ progress_VIII.txt | 237 ++++++++++ progress_X.txt | 589 ++++++++++++++++++++++++ progress_XI.txt | 373 +++++++++++++++ progress_XII.txt | 436 ++++++++++++++++++ progress_XIII.txt | 375 +++++++++++++++ progress_XIV.txt | 279 ++++++++++++ progress_XIX.txt | 384 ++++++++++++++++ progress_XV.txt | 151 +++++++ progress_XVI.txt | 213 +++++++++ progress_XVII.txt | 235 ++++++++++ progress_XVIII.txt | 288 ++++++++++++ progress_XX.txt | 1077 ++++++++++++++++++++++++++++++++++++++++++++ progress_XXI.txt | 192 ++++++++ vvz/src/scraper.py | 528 ++++++++++++++-------- 20 files changed, 6088 insertions(+), 200 deletions(-) create mode 100644 progress.txt create mode 100644 progress_I.txt create mode 100644 progress_II.txt create mode 100644 progress_IX.txt create mode 100644 progress_VI.txt create mode 100644 progress_VII.txt create mode 100644 progress_VIII.txt create mode 100644 progress_X.txt create mode 100644 progress_XI.txt create mode 100644 progress_XII.txt create mode 100644 progress_XIII.txt create mode 100644 progress_XIV.txt create mode 100644 progress_XIX.txt create mode 100644 progress_XV.txt create mode 100644 progress_XVI.txt create mode 100644 progress_XVII.txt create mode 100644 progress_XVIII.txt create mode 100644 progress_XX.txt create mode 100644 progress_XXI.txt diff --git a/progress.txt b/progress.txt new file mode 100644 index 0000000..9e71790 --- /dev/null +++ b/progress.txt @@ -0,0 +1,2 @@ + +010563 diff --git a/progress_I.txt b/progress_I.txt new file mode 100644 index 0000000..3f66930 --- /dev/null +++ b/progress_I.txt @@ -0,0 +1,86 @@ +010563 +010560 +010460 +010160 +010035a +010044b +010049a +010049b +010035 +010040 +010041 +010042 +010043 +010045 +010047 +010048 +010044a +010133 +010036 +010124 +010103 +010015 +010120 +010102 +010100 +010201 +010220 +010200 +010202 +010321 +010302 +010303 +010420 +010400 +010422 +010427 +010500 +010527 +010520 +010601 +210002 +210003 +210055 +210001 +010731 +060006 +010226 +010227 +010232 +010228 +010300 +010533 +010534 +010136 +010521 +010523 +010003 +010233 +010426 +010128 +010129 +010229 +010230 +010328 +020043 +010402 +010424 +010425 +010524 +010621 +210023 +010525 +010231 +010430 +010531 +010150 +010126 +010135 +010137 +010301 +010322 +010323 +010404 +010501 +010526 +010138 diff --git a/progress_II.txt b/progress_II.txt new file mode 100644 index 0000000..97975a5 --- /dev/null +++ b/progress_II.txt @@ -0,0 +1,74 @@ +020000 +020001 +020002 +020003 +020004 +020005 +020017 +020006 +020007 +020008 +020009 +020018 +020019 +020010 +020021 +020011 +020020 +020022 +020013 +020023 +020015 +020016 +020014 +020113 +020024 +020030 +020031 +020040 +020041 +020042 +020033 +020043 +020034 +020044 +020053 +020082 +020083 +020070 +020081 +020050 +020051 +020052 +020054 +020055 +020062 +020071 +020084 +020085 +020057 +020056 +020086 +060006 +020110 +020111 +020120 +020090 +020112 +020091 +020106 +020105 +020115 +020122 +020095 +020093 +020096 +020092 +020121 +020116 +020123 +020124 +020097 +020134 +020137 +020038 diff --git a/progress_IX.txt b/progress_IX.txt new file mode 100644 index 0000000..45b6443 --- /dev/null +++ b/progress_IX.txt @@ -0,0 +1,348 @@ +090001 +090002 +090011 +090013 +090012 +090014 +091100 +090700 +090300 +090100 +090200 +090400 +090104 +091101 +090101 +090754 +090905 +090951 +090952 +090908 +090600 +090202 +210038 +090601 +090903 +090902 +090901 +090904 +090907 +090906 +090201 +090203 +091000 +091003 +090001 +090002 +090001 +090002 +090011 +090013 +090012 +090014 +090012 +090001 +090002 +090011 +090013 +090014 +091100 +090700 +090300 +090100 +090200 +090400 +090104 +091101 +090101 +090754 +090754 +090905 +090951 +090952 +090908 +090600 +090202 +210038 +090601 +090903 +090902 +090901 +090904 +090907 +090906 +090905 +090952 +090951 +090908 +090200 +090600 +090202 +090201 +090601 +090203 +210038 +091000 +091003 +091002 +091001 +090402 +090400 +091054 +091007 +091007 +090305 +090403 +090405 +091000 +091003 +091002 +091001 +091004 +091005 +091006 +090405 +091054 +091009 +090402 +090400 +090401 +091007 +090702 +091012 +091010 +090407 +090305 +090403 +090406 +090702 +090404 +090407 +090800 +090801 +090802 +090851 +090703 +090505 +090803 +090500 +090104 +090100 +090102 +090105 +090101 +090505 +090704 +210051 +210038 +090800 +090801 +090802 +090703 +090505 +090851 +090803 +090500 +090100 +090104 +090102 +090105 +090101 +090505 +090704 +210038 +210051 +090014 +090301 +090300 +090303 +090304 +090302 +090305 +090306 +090307 +090352 +090203 +090308 +090352 +090306 +090203 +070120 +070121 +070020 +070021 +070025 +070022 +090800 +090801 +090902 +090903 +090901 +090907 +090904 +090906 +090905 +091000 +091001 +091002 +091003 +091004 +091005 +091006 +091005 +091006 +091004 +080006 +080007 +073019 +073018 +073010 +073011 +073011b +070011 +070010 +070032 +070035 +070030 +090016 +090151 +090016 +090651 +090653 +090654 +090652 +090255 +090655 +090651 +090251 +090253 +090652 +090253 +090653 +090654 +090254 +090652 +090655 +090255 +090450 +090403 +091012 +090403 +090406 +090404 +090403 +090406 +090404 +090451 +090406 +090403 +090404 +091012 +091010 +090451 +090406 +090403 +090404 +090451 +090406 +090403 +090404 +090850 +090554 +090553 +210027 +090553 +090554 +210027 +090150 +090850 +090554 +090750 +090553 +210027 +090553 +090554 +090750 +210027 +090150 +090850 +090951 +090952 +090802 +090356 +090353 +090354 +090352 +090350 +090407 +090352 +090350 +090354 +090351 +090850 +090951 +090952 +090802 +090356 +091007 +091012 +090407 +090654 +090653 +090662 +090663 +090651 +090654 +090653 +090662 +090663 +090553 +090554 +090750 +090552 +090551 +090550 +090850 +090553 +090554 +090750 +210027 +090552 +090550 +090551 +090450 +090451 +090406 +090403 +090404 +091012 +091010 +090451 +090406 +090403 +090404 +090451 +090406 +090403 +090404 +090700 +090251 +090652 +090253 +090254 +090652 +090255 +090554 +090451 +090700 +090750 +090553 +210027 +090554 +210027 +090553 +090750 +090150 +090451 +090700 +090002 diff --git a/progress_VI.txt b/progress_VI.txt new file mode 100644 index 0000000..e112a3d --- /dev/null +++ b/progress_VI.txt @@ -0,0 +1,230 @@ +060000 +060006 +060009 +060010 +060012 +060002 +060020 +060021 +060023 +060024 +060026 +060028 +060027 +060025 +060032 +060040 +060046 +060049 +060052 +060054 +060059 +060055 +060060 +060072 +060074 +060076 +060079 +060070 +060083 +060086 +060087 +060091 +060099 +060080 +060092 +060110 +060100 +060103 +060106 +060115 +060111 +060117 +060119 +060116 +060118 +060113 +060134 +060136 +060132 +060125 +060124 +060126 +060123 +060122 +060149 +060142 +060141 +060145 +060148 +060169 +060153 +060150 +060152 +060168 +060189 +060174 +060173 +060172 +060171 +060170 +060192 +060190 +060195 +060198 +060199 +060341 +060220 +060221 +060241 +060252 +060253 +060250 +060260 +060264 +060261 +060282 +060281 +060292 +060290 +060291 +060301 +060323 +060320 +060311 +060317 +060315 +060318 +060366 +060360 +060369 +060400 +060403 +060406 +060410 +060420 +060431 +060442 +060450 +060451 +060455 +060452 +060432 +060457 +060440 +060425 +060424 +060459 +060441 +060421 +060422 +060423 +060456 +060470 +060471 +060476 +060480 +060500 +060503 +060520 +060522 +060526 +060527 +060550 +060549 +060579 +060585 +060533 +060534 +060556 +060557 +060544 +060580 +060571 +060551 +060701 +060702 +060703 +060704 +060705 +060707 +060708 +060709 +060710 +060711 +060712 +060729 +060730 +060731 +060732 +060733 +060734 +060735 +060736 +060737 +060738 +060739 +060740 +060742 +060743 +061020 +061030 +061010 +061050 +061055 +061060 +060602 +060610 +060631 +060605 +060646 +060621 +060006 +060570 +060760 +060761 +060762 +060763 +060764 +060765 +060766 +060770 +060771 +060772 +060773 +060774 +060775 +060776 +060777 +060778 +060779 +060780 +060781 +060800 +060801 +060802 +060810 +060813 +060820 +060821 +060822 +060823 +060824 +060825 +060826 +060840 +060841 +060842 +060900 +060901 +060902 +060903 +060904 +060767 +060803 +060811 +060812 +060706 +060741 +060804 +060632 diff --git a/progress_VII.txt b/progress_VII.txt new file mode 100644 index 0000000..fe0619e --- /dev/null +++ b/progress_VII.txt @@ -0,0 +1,191 @@ +070003 +070004 +070005 +070010 +070011 +070011a +070011b +070020 +070021 +070025 +070022 +070030 +070032 +070035 +070031 +070120 +070121 +070100 +070101 +070080 +070040 +070041 +070042 +071005 +071010 +072181 +072184 +072063 +072060 +072003 +072044 +072249 +072221 +072701 +072220 +072140 +072141 +072180 +072183 +072011 +072010 +072002 +072042 +072043 +072150 +072151 +072155 +072156 +072157 +072152 +072098 +072096 +072015 +072015a +072017 +072016 +073005 +073007 +073154 +073132 +073133 +073134 +073101 +073102 +073013 +073041 +073006 +073099 +073602 +073601 +073156 +073157 +073155 +073040 +073604 +073603 +073605 +073250 +073063 +073800 +073140 +073141 +073009 +073143 +073010 +073011 +073011b +073000 +073002 +073003 +073004 +073008 +073018 +073019 +073043 +073045 +073046 +073500 +073502 +074602 +074210 +074800 +074090 +074322 +074335 +074207 +074208 +074209 +074311 +074310 +074050 +074051 +074206 +074082 +074170 +074171 +074003 +074086 +074000 +074001 +074085 +074204 +074703 +074702 +075126 +074035 +074036 +074045 +074080 +074081 +074070 +074555 +074700 +074280 +074290 +074084 +074258 +074259 +074502 +074507 +074509 +074503 +074504 +074517 +074101 +074102 +074120 +075281 +075155 +075231 +075230 +075267 +075260 +075261 +075262 +075561 +075560 +075540 +075300 +075301 +075341 +075340 +075410 +075701 +075562 +075270 +075550 +075010 +075220 +075016 +075274 +075510 +075500 +076000 +076001 +076010 +076012 +076015 +076016 +076020 +076030 +170007 +170007a +076005 +170007b +170007c +076011 +170007d +076040 +076041 +070004 diff --git a/progress_VIII.txt b/progress_VIII.txt new file mode 100644 index 0000000..c54d0f7 --- /dev/null +++ b/progress_VIII.txt @@ -0,0 +1,237 @@ +080024 +080228 +080236 +080240 +080249 +080261 +080246 +080311 +080324 +080336 +080342 +080348 +080351 +080354 +080355 +080356 +080001 +080131A +080101a +080101b +080101c +080101d +080101e +080101f +080101g +080101h +080101i +080101j +080101k +080101l +080101m +080101n +080101o +080101p +080101q +080002 +080003 +080102 +080103 +080004 +080134 +080135 +080136 +080104a +080104b +080104c +080104d +080137 +080005 +080105a +080105b +080105c +080006 +080007 +080106 +080014 +080114 +080008 +080009 +080108a +080109a +080109b +080108b +080010 +080140c +080140d +080140a +080140b +080011 +080016 +080141 +080012 +080013 +080113 +080653 +080203 +080204 +080201 +080202 +080206 +080207 +080208 +080209 +080015 +080115 +080210 +080212 +080213 +080235 +080243 +080220 +080219 +080215 +080217 +080218 +080221 +080225 +080226 +080801 +080116 +080227 +080229 +080230 +080117 +080232 +080231 +080233 +080234 +080241 +080018 +080118 +080242 +080119 +080238 +080237 +080239 +080120 +080244 +080245 +080247 +080248 +080121 +080250 +080252 +080251 +080122 +080254 +080255 +080256 +080257 +080258 +080253 +080022 +080259 +080260 +080123 +080263 +210002 +210030 +080126 +080264 +080265 +080125 +080129 +080266 +060076 +090302 +090303 +090304 +060010 +060080 +060083 +030034 +030035 +030040 +030075 +030081 +040013 +040116 +040196 +040085 +050320 +050322 +112101 +112361 +210001 +050010 +080655 +080302 +080303 +080304 +080301 +080300 +210028 +080654 +080306 +080308 +080307 +080309 +060009 +060150 +060141 +060152 +060091 +060134 +060116 +030564 +030086 +030090 +030102 +030113 +090353 +090352 +090350 +040210 +040170 +050321 +050323 +040163 +080051 +080151a +080151b +080314 +080310 +080312 +080313 +080315 +080316 +080317 +080318 +080320 +080321 +080802 +080656 +080322 +080323 +080326 +080658 +080327 +080328 +080329 +080659 +080332 +080330 +080331 +080660 +080343 +080344 +080661 +080345 +080662 +080346 +080347 +080679 +080335 +080333 +080334 diff --git a/progress_X.txt b/progress_X.txt new file mode 100644 index 0000000..58f7c32 --- /dev/null +++ b/progress_X.txt @@ -0,0 +1,589 @@ +100007 +100006 +100450 +100451 +100456 +100457 +100458 +100032 +100101 +100108 +100109 +100130 +100131 +100139 +100150 +100151 +100152 +100153 +100159 +100280 +100281 +100287 +100289 +100283 +100138 +100160 +100161 +100168 +100169 +100170 +100171 +100178 +100180 +100181 +100188 +100200 +100201 +100208 +100209 +100220 +100229 +100230 +100231 +100238 +100239 +100189 +100128 +100129 +100240 +100241 +100248 +100260 +100261 +100265 +100290 +100299 +100320 +100350 +100351 +100358 +100121 +100352 +100300 +100002 +100374 +100033 +100034 +100014 +100000 +100001 +100008 +100012 +100009 +100019 +100016 +100011 +100013 +100184 +100163 +100164 +100215 +100233 +100285 +100286 +100255 +100513 +100611 +100585 +100099 +100514 +100070 +100071 +100763 +100764 +100567 +100572 +100570 +100583 +100582 +100569 +100580 +100584 +100576 +100060 +100065 +076020 +100603 +100609 +100615 +076030 +100607 +100099 +100617 +100601 +076012 +076010 +100717 +100626 +100630 +100616 +100513 +100611 +100585 +100099 +100070 +100071 +100514 +100763 +100764 +100750 +100765 +100767 +100768 +100771 +100766 +100762 +100769 +100759 +100772 +100007 +100006 +100032 +100458 +100451 +100456 +100450 +100457 +100101 +100131 +100130 +100152 +100153 +100151 +100150 +100280 +100281 +100283 +100287 +100289 +100129 +100138 +100108 +100109 +100139 +100159 +100160 +100161 +100170 +100171 +100181 +100180 +100201 +100200 +100220 +100231 +100230 +100168 +100178 +100169 +100229 +100238 +100239 +100208 +100188 +100189 +100209 +100240 +100241 +100260 +100261 +100265 +100290 +100320 +100350 +100351 +100128 +100121 +100352 +100300 +100299 +100358 +100248 +100002 +100374 +100033 +100034 +100008 +100001 +100000 +100012 +100009 +100011 +100019 +100016 +100013 +100184 +100163 +100164 +100215 +100233 +100285 +100286 +100255 +100513 +100585 +100611 +100099 +100514 +100071 +100070 +100763 +100764 +100570 +100567 +100572 +100583 +100582 +100580 +100584 +100569 +100576 +100060 +100065 +076020 +100603 +100609 +100615 +076030 +100607 +100099 +100601 +100617 +076012 +076010 +100717 +100626 +100630 +100616 +100513 +100585 +100611 +100099 +100071 +100070 +100514 +100763 +100764 +100750 +100765 +100767 +100768 +100771 +100766 +100762 +100769 +100759 +100772 +100010 +100007 +100140 +100141 +100099 +100017 +100101 +100108 +100109 +100139 +100138 +100151 +100150 +100130 +100131 +100283 +100280 +100287 +100289 +100159 +100168 +100169 +100188 +100178 +100161 +100160 +100181 +100180 +100170 +100171 +100189 +100208 +100209 +100201 +100230 +100231 +100200 +100238 +100239 +100121 +100248 +100240 +100241 +100220 +100260 +100261 +100265 +100290 +100229 +100299 +100358 +100352 +100350 +100351 +100300 +100320 +100128 +100002 +100374 +100019 +100008 +100009 +100012 +100004 +100011 +100013 +100370 +100006 +100101 +100152 +100151 +100153 +100150 +100131 +100130 +100281 +100280 +100283 +100287 +100289 +100138 +100108 +100109 +100139 +100159 +100160 +100161 +100171 +100170 +100181 +100180 +100201 +100200 +100230 +100231 +100220 +100178 +100168 +100169 +100229 +100238 +100239 +100208 +100188 +100189 +100209 +100240 +100241 +100351 +100350 +100261 +100732 +100290 +100265 +100320 +100248 +100128 +100129 +100260 +100121 +100352 +100300 +100299 +100358 +100377 +100378 +100002 +100033 +100034 +100014 +100001 +100008 +100000 +100012 +100009 +100016 +100019 +100011 +100013 +100141 +100140 +100017 +100010 +100370 +100108 +100109 +100139 +100138 +100159 +100101 +100151 +100150 +100130 +100131 +100280 +100283 +100287 +100289 +100168 +100169 +100188 +100178 +100161 +100160 +100181 +100180 +100170 +100171 +100189 +100208 +100209 +100201 +100230 +100231 +100200 +100238 +100239 +100128 +100129 +100121 +100248 +100240 +100241 +100220 +100260 +100261 +100265 +100290 +100229 +100299 +100358 +100320 +100352 +100350 +100351 +100300 +100732 +100378 +100377 +100002 +100019 +100008 +100009 +100012 +100004 +100013 +100011 +100103 +100808 +100809 +100806 +100059 +100813 +100807 +100801 +100802 +100803 +100006 +100370 +100101 +100150 +100151 +100152 +100153 +100283 +100281 +100130 +100131 +100280 +100200 +100201 +100220 +100230 +100231 +100180 +100181 +100160 +100161 +100170 +100171 +100290 +100350 +100351 +100240 +100241 +100732 +100320 +100265 +100260 +100261 +100121 +100352 +100002 +100377 +100378 +100300 +100034 +100033 +100014 +100008 +100001 +100000 +100012 +100009 +100016 +100019 +100011 +100013 +100103 +100808 +100809 +100806 +100059 +100813 +100807 +100801 +100802 +100803 +100975 +100960 +100961 +100962 +100976 +100908 +100980 +100977 +100978 +100979 +100917 +100916 +100971 +100968 +100927 +100970 +070040 +070041 +070042 +070080 +071005 +100965 +100966 +100967 +100963 +100964 +100972 +100973 +100923 +100924 +100971 +100968 +100970 +100927 diff --git a/progress_XI.txt b/progress_XI.txt new file mode 100644 index 0000000..f20eb53 --- /dev/null +++ b/progress_XI.txt @@ -0,0 +1,373 @@ +112211 +112212 +112213 +112214 +112215 +112216 +112217 +112231 +112232 +112233 +112234 +112235 +112236 +112237 +112238 +112239 +112271 +112121 +112122 +112123 +112124 +112125 +112129 +112130 +112131 +112132 +112133 +112101 +112111 +112241 +112341 +112343 +112344 +112345 +112346 +112347 +112348 +112349 +112351 +112352 +112353 +112354 +112355 +112356 +112357 +112359 +112161 +112162 +112164 +112165 +112166 +112167 +112169 +112171 +112172 +112173 +112178 +112181 +112182 +112183 +112151 +112152 +112157 +112158 +112441 +112432 +112433 +112434 +112435 +112442 +112443 +112444 +112445 +112446 +112447 +112448 +112449 +112450 +112451 +112452 +112453 +112454 +112361 +112551 +112532 +112539 +112540 +112542 +112543 +112544 +112545 +112546 +112547 +112549 +112552 +112553 +112554 +112440 +112436 +112439 +112457 +112555 +112616 +112617 +112619 +118411 +118412 +112621 +112622 +112623 +112921 +112931 +112358 +112712 +112713 +112714 +112715 +112716 +112717 +112718 +112719 +112720 +112721 +112722 +112723 +112724 +112725 +112726 +112727 +112915 +117113 +117440 +117442 +118925 +118417 +118418 +118928 +110005 +430007 +118920 +117031 +118111 +118213 +118127 +118128 +115111 +115112 +118211 +115113 +115114 +115115 +115126 +115127 +115128 +115131 +115132 +115133 +115134 +115135 +115136 +117021 +117022 +115149 +115145 +115120 +117031 +118711 +118513 +118515 +118518 +118156 +118159 +118516 +117021 +117022 +118925 +117113 +117442 +114817 +118417 +114816 +118910 +110005 +110013 +118113 +118912 +118914 +118916 +118917 +118918 +118919 +118920 +118923 +118924 +118927 +118930 +118922 +430007 +118920 +117433 +117412 +117031 +117423 +117431 +117441 +117111 +117411 +117435 +117436 +117433 +117434 +117021 +117022 +118925 +117440 +117113 +117442 +118417 +110005 +118920 +118923 +118916 +118918 +118912 +118113 +118917 +118919 +118914 +118924 +118926 +118930 +118922 +430007 +118920 +117433 +117434 +112211 +112212 +112213 +112214 +112215 +112216 +112217 +112231 +112232 +112233 +112234 +112235 +112236 +112237 +112238 +112239 +112271 +112111 +112121 +112129 +112130 +112131 +112132 +112133 +112241 +112341 +112343 +112344 +112345 +112346 +112347 +112348 +112349 +112351 +112352 +112353 +112354 +112355 +112356 +112357 +112359 +112161 +112162 +112164 +112165 +112169 +112171 +112178 +112181 +112182 +112166 +112167 +112183 +112172 +112173 +112151 +112152 +112157 +112158 +112432 +112433 +112434 +112435 +112441 +112442 +112443 +112444 +112445 +112446 +112447 +112448 +112449 +112450 +112451 +112452 +112453 +112454 +115158 +115146 +115156 +115153 +115154 +115157 +115143 +115160 +115144 +115155 +115148 +115147 +115141 +115142 +115331 +115332 +115333 +115334 +115335 +115336 +115161 +115162 +115163 +115164 +115165 +115166 +115167 +115168 +115169 +115311 +115312 +115313 +115314 +115315 +118131 +118132 +118112 +118032 +118665 +118613 +110009 +208623 +117451 +030005 +119218 +110012 +212006 +119222 +112916 +118921 +212501 +212045 +118512 +118511 +11902 +030131 +030127 +212103 +119220 +110020 diff --git a/progress_XII.txt b/progress_XII.txt new file mode 100644 index 0000000..e0a470e --- /dev/null +++ b/progress_XII.txt @@ -0,0 +1,436 @@ +121001 +121002 +121003 +123001 +150100 +150101 +121201 +129200 +129205 +160039 +160040 +187110 +123002 +123003 +123004 +123005 +123007 +123008 +123009 +123011 +123012 +150104 +150105 +129200 +129205 +123000 +125000 +125001 +125002 +125003 +125004 +125010 +125011 +125012 +125013 +125014 +125015 +125016 +129200 +129205 +127006 +127009 +127012 +127013 +127021 +150106 +150107 +178008 +127018 +127022 +127506 +127518 +127519 +129003 +129004 +129009 +129010 +129011 +129020 +129021 +129022 +129023 +129024 +129025 +129031 +129032 +129041 +129103 +129201 +129209 +129210 +129217 +129231 +127000 +127006 +127009 +127010 +127012 +150106 +150107 +127021 +127022 +127506 +127518 +127519 +129001 +129002 +129003 +129004 +129008 +129009 +129010 +129011 +129020 +129021 +129022 +129027 +129101 +129212 +129219 +127009 +127002 +127006 +127010 +127012 +129102 +150106 +150107 +127022 +127506 +127511 +127518 +127519 +129001 +129002 +129003 +129004 +129008 +129014 +129016 +129027 +135110 +127006 +127009 +127016 +127020 +127024 +127026 +150106 +150107 +150108 +150109 +127022 +129009 +129010 +129020 +129023 +129024 +129025 +129028 +129029 +129030 +129031 +129032 +129033 +129038 +129039 +129040 +129041 +129044 +129045 +129046 +129104 +127006 +127009 +127016 +127020 +127024 +127026 +150106 +150107 +150108 +150109 +127021 +127022 +129001 +129002 +129009 +129010 +129020 +129023 +129024 +129025 +129028 +129029 +129030 +129031 +129032 +129033 +129038 +129039 +129041 +129105 +129110 +127517 +128032 +129202 +129203 +129204 +129206 +129208 +129213 +129215 +129216 +129218 +129221 +129224 +129226 +121001 +121002 +131030 +137225 +150100 +150101 +187260 +129200 +129205 +160039 +160040 +123002 +123003 +123004 +150104 +150105 +121003 +123005 +123007 +123302 +131070 +133020 +135340 +150106 +150107 +129200 +129205 +123000 +123008 +123009 +123011 +123012 +125006 +125010 +125011 +125015 +125018 +129039 +135030 +135050 +135080 +135212 +137400 +137540 +125004 +129200 +129205 +137060 +137070 +160039 +160040 +127016 +127020 +129222 +129223 +150108 +150109 +129020 +135130 +135155 +135220 +137110 +137130 +137150 +137310 +137430 +137470 +137600 +137840 +139030 +139060 +139170 +139250 +139350 +139513 +139920 +127024 +127026 +129020 +129023 +129024 +129025 +129030 +129031 +129032 +129033 +129045 +129046 +129212 +129219 +135130 +127024 +127026 +129023 +129024 +129025 +129028 +129029 +129030 +129031 +129032 +129033 +129201 +129217 +129231 +127018 +127024 +127026 +129030 +129031 +129032 +129033 +129038 +129039 +129040 +129044 +129045 +129046 +129201 +129217 +129231 +178008 +129110 +129227 +129228 +129229 +129230 +125015 +127006 +127009 +128032 +129009 +129010 +129206 +129213 +129216 +129226 +129909 +139180 +139260 +129218 +125500 +125501 +125502 +125504 +125507 +125505 +127503 +127504 +127505 +127506 +127507 +127508 +127509 +127511 +127513 +127516 +127517 +127518 +127519 +440108 +125509 +127512 +129224 +129204 +125510 +125500 +125507 +125801 +125805 +177159 +177304 +177804 +125806 +125807 +125815 +125816 +125818 +127518 +129009 +129010 +129021 +129022 +177104 +125505 +125510 +125814 +125817 +127018 +127511 +127517 +127519 +139080 +129951 +129952 +129953 +129954 +129955 +129956 +129957 +129959 +129960 +129961 +129962 +129963 +129964 +129965 +129966 +129969 +129970 +121001 +121002 +121601 +121602 +121603 +125505 +125603 +127000 +127022 +129015 +129215 +129603 +129970 +125017 +128032 +129203 +129204 +129800 +129904 +129907 +129908 +129909 +129910 +129911 +129912 +135250 +121002 +129232 diff --git a/progress_XIII.txt b/progress_XIII.txt new file mode 100644 index 0000000..4facd46 --- /dev/null +++ b/progress_XIII.txt @@ -0,0 +1,375 @@ +130002 +121001 +121002 +131015 +131020 +131070 +131072 +150100 +150101 +131010 +160048 +160049 +187261 +130001 +135001 +135050 +135220 +137540 +135030 +135130 +135212 +135080 +137310 +135155 +135010 +135610 +135001 +137090 +135050 +135070 +135060 +135110 +135610 +135350 +135020 +137650 +135001 +135250 +135050 +125603 +129015 +125505 +135020 +135060 +135610 +135070 +121603 +135001 +137090 +135050 +135020 +135230 +135245 +137650 +135511 +137400 +135178 +135001 +121001 +150100 +131015 +160048 +187261 +131010 +131020 +131070 +131072 +150104 +150105 +150106 +150107 +135001 +133010 +133020 +133520 +127000 +135050 +131070 +150100 +150101 +180112 +131050 +131052 +131015 +187110 +131060 +187111 +150104 +150105 +121001 +121002 +133020 +133080 +133060 +135160 +135180 +135170 +135190 +135001 +251240 +251241 +251242 +135210 +135020 +135230 +135245 +137650 +135511 +137400 +135178 +135210 +135001 +251240 +251241 +251242 +130002 +121601 +121602 +131020 +131040 +131070 +131072 +150130 +150131 +131015 +160048 +160049 +187261 +133020 +133040 +251240 +251241 +251242 +150104 +150105 +133520 +133030 +135050 +135130 +137310 +135200 +135040 +135090 +135120 +141293 +135020 +135200 +135040 +135090 +135120 +141293 +133010 +135350 +135020 +135200 +135040 +135090 +135120 +141293 +135030 +135610 +135220 +135212 +137540 +135155 +135080 +137020 +135110 +135060 +135070 +135178 +135610 +137020 +135250 +137650 +135511 +135230 +137400 +135178 +135245 +137020 +121601 +121602 +150130 +160048 +187261 +135120 +131040 +131015 +131020 +131070 +131072 +150104 +150105 +133040 +133520 +133030 +133020 +251240 +251241 +251242 +141293 +135200 +135040 +135090 +139970 +137225 +137610 +137060 +137070 +135360 +137080 +139160 +137160 +139150 +118925 +072015a +072015 +072016 +072017 +139403 +139404 +139250 +139170 +139310 +139080 +139920 +137365 +139260 +131018 +129603 +137120 +137270 +440108 +137130 +137150 +137360 +137600 +139060 +139310 +139350 +139403 +139404 +139080 +139170 +137030 +137040 +137120 +137270 +139270 +139400 +139070 +139120 +137560 +139360 +139050 +137017 +137150 +139020 +139401 +139406 +139530 +139910 +440620 +139100 +137150 +137360 +139310 +139403 +139404 +139408 +137365 +139190 +139020 +139530 +137017 +139910 +137150 +139560 +139100 +440620 +137030 +137120 +139120 +139190 +139560 +137040 +139070 +440620 +139360 +139050 +137130 +137150 +137360 +137600 +139060 +139310 +139350 +139190 +139560 +139170 +440401 +440402 +440420 +440701 +440702 +440703 +139401 +139020 +137017 +139100 +440108 +440602 +440606 +440620 +440508 +440619 +440604 +125501 +125507 +440524 +440607 +440603 +440511 +127507 +135150 +137010 +137245 +137440 +137470 +137995 +139030 +139300 +139760 +139920 +139100 +139513 +139970 +137110 +139110 +141407 +139200 +139210 +139180 +139250 +139980 +139130 +137670 +139010 +139740 +139150 +139950 +141208 +074602 +139139 +139207 +139026 +139039 +139043 +139045 +139090 +138920 +139770 +139780 +139790 +139800 +139810 +139820 +139830 +139840 +139850 +139870 +139700 +135900 +121001 diff --git a/progress_XIV.txt b/progress_XIV.txt new file mode 100644 index 0000000..9d81bbd --- /dev/null +++ b/progress_XIV.txt @@ -0,0 +1,279 @@ +150110 +150111 +141041 +141129 +141018 +141019 +251280 +251281 +251282 +144002 +144004 +140000 +141106 +141129 +150110 +150111 +160033 +160034 +141481 +142161 +141180 +141086 +150114 +150115 +141218 +141026 +144001 +144003 +140020 +142104 +142105 +144012 +141003 +141289 +141120 +141087 +141065 +141391 +141203 +141264 +212000 +141209 +141106 +140000 +144101 +141215 +141007 +141042 +142220 +142081 +142002 +143160 +143121 +212501 +212006 +209800 +141083 +141069 +140005 +139070 +135350 +137270 +137040 +141386 +141020 +141021 +212045 +141145 +141106 +141167 +141268 +140010 +140003 +144101 +141007 +141407 +142081 +141403 +141085 +141084 +141083 +141079 +141064 +141042 +141106 +141167 +141268 +140003 +144101 +141183 +141145 +142380 +142379 +142180 +142063 +143289 +143264 +143121 +141482 +141386 +141380 +141301 +141272 +141187 +141133 +141132 +141125 +141069 +141384 +141064 +141106 +141167 +141268 +140003 +144101 +141403 +141401 +141083 +141007 +142081 +141407 +141085 +141084 +141082 +141080 +141079 +141064 +141042 +135130 +141106 +141167 +141268 +140003 +144101 +141133 +141272 +141187 +141125 +142263 +142180 +142063 +142262 +143289 +143264 +143121 +141482 +141386 +141384 +141380 +141361 +141301 +141269 +141225 +141222 +141215 +141183 +141132 +141064 +141042 +141296 +141206 +141106 +141167 +141268 +140010 +140003 +144101 +141160 +141222 +141215 +141042 +142203 +142183 +142162 +143202 +143160 +143121 +212006 +209800 +141401 +141165 +141007 +135350 +140013 +141206 +141145 +141106 +141167 +141268 +140003 +144101 +141225 +141222 +141372 +141042 +142220 +142162 +143060 +212006 +209800 +160228 +160229 +141165 +141160 +141069 +141064 +141296 +141476 +141106 +140010 +141167 +141268 +140010 +140003 +141361 +144101 +141291 +141296 +142101 +143282 +143280 +143264 +160228 +141374 +141364 +141363 +141285 +141368 +140003 +141260 +141478 +142270 +142262 +251231 +251230 +144103 +139940 +141482 +141267 +141269 +139230 +141424 +141476 +143263 +141422 +143264 +142263 +139040 +142264 +142267 +142268 +142265 +142266 +143060 +141109 +140008 +251231 +141267 +142269 +144103 +141482 +141269 +139940 +141476 +143264 +143263 +142268 +142267 +142266 +142265 +142264 +142263 +141422 +139040 +143060 +142262 +141109 +140008 +150111 diff --git a/progress_XIX.txt b/progress_XIX.txt new file mode 100644 index 0000000..38da8d7 --- /dev/null +++ b/progress_XIX.txt @@ -0,0 +1,384 @@ +190000 +190001 +190002 +190002a +190002b +190003 +190003a +190003b +190004 +150140 +150141 +187112 +190005 +190006 +190007 +160035 +160036 +160051 +187540a +187540b +150144 +190570 +190530 +190564 +190511 +190512 +190515 +190473 +190474 +190475 +190476 +190478 +190595 +190472 +190477 +190015 +190016 +190800 +190017 +190018 +190019 +190029 +190030 +190031 +190020 +190021 +190022 +190023 +190024 +190025 +190026 +190027 +190028 +190032 +190033 +190034 +190038 +190039 +190040 +190041 +190042 +190043 +190060 +190061 +190062 +190084 +190085 +190086 +190148 +190149 +190150 +190179 +190180 +190181 +190063 +190064 +190065 +190161 +190162 +190164 +190165 +190243 +190244 +190245 +190246 +190247 +190248 +190074 +190075 +190168 +190169 +190170 +190171 +190172 +190174 +190175 +190254 +190255 +190256 +190262 +190263 +190264 +190271 +190272 +190276 +190277 +190279 +190280 +190281 +190282 +190283 +190284 +190288 +190289 +190293 +190294 +190296 +190297 +190298 +190299 +190304 +190305 +190307 +190308 +190312 +190313 +190315 +190316 +190317 +190318 +190319 +190320 +190322 +190323 +190329 +190330 +190331 +190332 +190334 +190336 +190337 +190338 +190339 +190340 +190345 +190346 +190348 +190349 +190350 +190351 +190353 +190354 +190356 +190357 +190359 +190360 +190362 +190363 +190365 +190366 +190368 +190369 +190370 +190371 +190374 +190375 +190376 +190377 +190378 +190379 +190381 +190382 +190389 +190390 +190392 +190393 +190395 +190396 +190398 +190399 +190402 +190403 +190409 +190412 +190413 +190414 +190415 +190416 +190417 +190418 +190419 +190420 +190422 +190423 +190426 +190427 +190429 +190430 +190431 +190432 +190433 +190434 +190437 +190438 +190441 +190442 +190445 +190446 +190457 +190458 +190459 +190464 +190465 +190470 +190471 +212402 +212403 +190509 +190522 +194301 +204742 +190508 +190546 +190549 +190550 +190551 +190553 +190558 +190559 +190560 +190563 +190579 +190536 +190525 +190547 +212104 +190545 +190479 +190583 +190584 +190585 +190586 +190587 +190588 +190590 +190592 +190594 +190596 +190667 +190670 +190600 +190597 +212105 +190599 +190610 +190626 +190627 +190628 +190702 +190703 +190541 +190542 +190538 +190539 +190540 +190574 +190573 +190622 +251260 +190519 +190510 +190526 +190534 +190514 +190637 +190638 +190639 +190640 +190641 +190642 +190643 +190644 +190645 +190646 +190647 +190648 +190649 +190650 +190651 +190652 +190653 +190654 +190655 +190656 +190658 +190659 +185095 +185720 +185750 +185751 +185983 +186100 +186110 +186125 +186156 +190552 +190555 +190665 +190676 +200131 +200504 +201001 +202450 +202451 +203010 +203111 +206521 +206522 +207311 +207506 +207519 +207708 +208341 +208443 +208444 +208601 +209041 +209267 +209271 +209272 +209806 +209812 +209822 +209831 +209840 +209841 +209852 +209849 +190571 +190561 +205613 +209263 +190520 +201910 +201908 +190701 +190801 +185730 +185731 +185770 +185771 +185932 +185933 +185952 +185953 +185972 +185973 +190700 +194101 +194102 +194103 +194104 +194201 +194202 +194302 +194401 +194402 +194403 +194714 +194715 +194716 +194717 +194718 +194720 +194719 +194721 +194722 +194723 +194724 +194727 +194726 +194725 +194901 +194902 diff --git a/progress_XV.txt b/progress_XV.txt new file mode 100644 index 0000000..d6f9387 --- /dev/null +++ b/progress_XV.txt @@ -0,0 +1,151 @@ +150070 +150071 +150072 +150073 +150074 +150075 +125500 +127507 +150100 +150101 +150104 +150105 +150106 +150107 +150108 +150109 +150110 +150111 +150114 +150115 +150120 +150121 +150124 +150125 +150130 +150131 +150134 +150135 +150140 +150141 +150144 +150200 +150201 +150202 +150203 +150204 +150205 +150206 +150207 +150208 +150209 +150210 +150211 +150214 +150215 +150216 +150217 +150222 +150223 +150224 +150225 +150228 +150229 +150230 +150231 +150236 +211028 +212002 +212011 +212017 +212018 +212022 +211043 +150410 +150412 +150502 +150504 +150509 +150515 +150521 +150522 +150532 +150537 +150540 +150542 +150546 +150564 +150566 +212123 +212129 +212140 +150570 +150575 +150903 +150582 +150583 +150600a +150600b +150600c +150614 +150615 +150617 +150623 +150624 +150625 +150628 +150636 +150637 +150900 +150901 +150902 +150905 +150907 +150908 +150909 +150910 +150912 +150913 +150915 +150916 +150922 +150925 +150926 +150931 +150071 +150150 +150151 +150151a +150160 +150161 +150180 +150195 +150237 +150240 +150244 +150245 +150256 +150257 +150260 +150261 +150266 +150267 +150270 +150271 +150272 +150273 +150276 +150278 +150279 +150280 +150281 +150282 +150283 +150290 +150292 +150293 +150294 +150295 +150297 +150298 +150299 diff --git a/progress_XVI.txt b/progress_XVI.txt new file mode 100644 index 0000000..020ccf9 --- /dev/null +++ b/progress_XVI.txt @@ -0,0 +1,213 @@ +160081 +160082 +160091 +160101 +160102 +160102 Z +160103 +160104 +150120 +150121 +160111 +160112 +150124 +150125 +160113 +160114 +160237 +160238 +160117 +160120 +160120a +160150 +160200 +160201 +160202 +160203 +160228 +160229 +160206 +160207 +160204 +160205 +160250 +160213 +160214 +160217 +160220 +160224 +160225 +160222 +160223 +160226 +160227 +160210 +160211 +160243 +160244 +160234 +160235 +160236 +160237 +160240 +160200 +160201 +160202 +160203 +160228 +160229 +160206 +160207 +160204 +160205 +160210 +160211 +160243 +160244 +160250 +160611 +160612 +160613 +160608 +160602 +160621 +160663 +160624 +160250 +160401 +160402 +160406 +160417 +160420 +160421 +160422 +160429 +160416 +160415 +160250 +160433 +160434 +160435 +160501 +160502 +160515 +160516 +160507 +160508 +160529 +160530 +160531 +160511 +160521 +160510 +160522 +160517 +160523 +160250 +160303 +160304 +160313 +160323 +160350 +160327 +160250 +160316 +160821 +160823 +160830 +160835 +160250 +160226 +160227 +160234 +160235 +160236 +160101 +160102 +160102 Z +160103 +160104 +160111 +160112 +160115 +160116 +160117 +160150 +160200 +160201 +160202 +160203 +160228 +160229 +160212 +160250 +160200 +160201 +160202 +160203 +160822 +160833 +160838 +160831 +160451 +160452 +160454 +160455 +160703 +160711 +160704 +160709 +160652 +160654 +160657 +160658 +160659 +160662 +160664 +160667 +160669 +160668 +160661 +160666 +160832 +160834 +160710 +160453 +160456 +160418 +160553 +160554 +160555 +160552 +160556 +160551 +160357 +160356 +160359 +160355 +160360 +160361 +160001 +160002 +160005 +160006 +160035 +160036 +160037 +160038 +160031 +160032 +160033 +160034 +160039 +160040 +160041 +160042 +160046 +160047 +160048 +160049 +160050 +160051 +160052 +160053 diff --git a/progress_XVII.txt b/progress_XVII.txt new file mode 100644 index 0000000..81234a0 --- /dev/null +++ b/progress_XVII.txt @@ -0,0 +1,235 @@ +170000 +170089 +170001 +170002 +170004a +170003 +170005a +170005b +170005c +176101 +170006 +170006a +170006b +170006c +170006d +170006e +170006f +170007 +170007a +170007b +170007c +170007d +150134 +150135 +170019 +170020 +170020a +170020b +170020c +170020d +170020g +170020h +170021 +170022 +170023 +170023a +170023b +170023c +170023d +170023e +170023f +170139 +170029 +170031a +170024 +170044 +170047 +170048 +170140 +170042 +170039 +170033 +170035 +170159 +170052 +170054 +170055 +170063 +170087 +170145 +170157 +170158 +170160 +170165 +170151 +170198 +170149 +177471 +170154 +170167 +170155 +170169 +170088 +170178 +170149 +170070 +170071 +170072 +170077 +170075 +170182 +170080 +170081 +170082 +170083 +170084 +170085a +170085b +170090 +170091 +170104 +170105 +170107 +170184 +170084 +170085a +170085b +170093a +170093b +170094a +170094b +170143a +170183 +170116 +170117 +170118 +170120 +170121 +170122 +170125 +170128 +170129 +170134 +170135 +170170 +170170a +170170b +170171 +170172a +170172b +170172c +170182 +170183 +170184 +170188 +170066 +170113 +176417 +176417 +177004 +150130 +150131 +160037 +160038 +176101 +176104 +176105 +187110 +187111 +176103 +176107 +176106 +176102 +176008 +176301 +176307 +176302 +176304 +176305 +176312 +176107 +176311 +176303 +176309 +176313 +176308 +176550 +176310 +0004 +176306 +176502 +176510 +176512 +176505 +176501 +176508 +176518 +176550 +176313 +176506 +176503 +176507 +176417 +177209 +178000 +177104 +177309 +177399 +177469 +177931 +177988 +177701 +177706 +177004 +177462 +177804 +177807 +177304 +177505 +177502 +177506 +177507 +177508 +177986 +177105 +177358 +177303 +177322 +177908 +178008 +170089 +177278 +177258 +177259 +177231 +177717 +177718 +177032 +177310 +177323 +177368 +177906 +177218 +177526 +177217 +177201 +177024 +177396 +177457 +177461 +177276 +177464 +177257 +139080 +177522 +177463 +177255 +177136 +177135 +177504 +177503 +177932 +177228 +177229 +177311 diff --git a/progress_XVIII.txt b/progress_XVIII.txt new file mode 100644 index 0000000..3139122 --- /dev/null +++ b/progress_XVIII.txt @@ -0,0 +1,288 @@ +180180 +180181 +180182 +150150 +150151 +150151a +180113 +180114 +180115 +180112 +180116 +180383 +180384 +180381 +180110 +180382 +180111 +180340 +180341 +180350 +180351 +180370 +180371 +180303 +180542 +180543 +180452 +180453 +180510 +180511 +180513 +180514 +180515 +180540 +180541 +180550 +180551 +180500 +180501 +180560 +180561 +180570 +180571 +184320 +184321 +180009 +180503 +181180 +181181 +181750 +181751 +181700 +181701 +181702 +181704 +181705 +181709 +181901 +181902 +181903 +181904 +181905 +181706 +181710 +181712 +181713 +181714 +181715 +181716 +181717 +181785 +181912 +181718 +181020 +181719 +181711 +181784 +181720 +181721 +181722 +181922 +190705 +190704 +181780 +181781 +184613 +184614 +181742 +181743 +181744 +181745 +181748 +181749 +181943 +181944 +186142 +186145 +188111 +188112 +181940 +185914 +181941 +181942 +181946 +181746 +181747 +181752 +181753 +181754 +181755 +181756 +181757 +181759 +181954 +188151a +188151b +181951 +181952 +181848 +181849 +181760 +181761 +181762 +181763 +181764 +181765 +181962 +183260 +181770 +181771 +181772 +181773 +181774 +181775 +181776 +181777 +181970 +181971 +181972 +181973 +181975 +181787 +181788 +181974 +181782 +181783 +181812 +181813 +181786 +181789 +137610 +181778 +181779 +181790 +181791 +160041 +160042 +188151c +188171a +188171b +188171c +188380 +188381 +182112 +180117 +180118 +182301 +182450 +182451 +184350 +183130 +183131 +183132 +183134 +183133a +183332 +183333 +183334 +186191 +186192 +186193 +186194 +186195 +186196 +186197 +186198 +180385 +180386 +190700 +184112 +184322 +209832 +184303 +184452 +184453 +184500 +184501 +184504 +184505 +184502 +184503 +184541 +184506 +184570 +184571 +185720 +185710 +185711 +185730 +185731 +185750 +185751 +185770 +185771 +209806 +209852 +185790 +185791 +185906 +185912 +185913 +185932 +185933 +184632 +185952 +185953 +185972 +185973 +185982 +185983 +185792 +185793 +185091 +185092 +185093 +185094 +185095 +185096 +186080 +186187 +208344 +186189 +186100 +186110 +186111 +186112 +186150 +186151 +186152 +186154 +186156 +186157 +186158 +186153 +186103 +186104 +186105 +186123 +186125 +186162 +186163 +186164 +186170 +186174 +186175 +186130 +186190 +186188 +180110a +180111a +176307 +187110 +187111 +187260 +187440 +187520 +187522 +187523 +187540a +187540b +187542 +190006 +160048 +160049 +187261 +121201 +187112 +187113 diff --git a/progress_XX.txt b/progress_XX.txt new file mode 100644 index 0000000..585dec1 --- /dev/null +++ b/progress_XX.txt @@ -0,0 +1,1077 @@ +200000 +200100 +200101 +200102 +200104 +200105 +200106 +200107 +200120 +200122 +200123 +200124 +200125 +200126 +200127 +200142 +202230 +200300 +200301 +200302 +200303 +200320 +200321 +200322 +200323 +200324 +200326 +200327 +200340 +200341 +200342 +200346 +200500 +200501 +200502 +200503 +200504 +200505 +200506 +200507 +200508 +200520 +200521 +200522 +200523 +200524 +200525 +200526 +200527 +200540 +200700 +200702 +200703 +200704 +200705 +200706 +200707 +200701 +200720 +200721 +200722 +200723 +200724 +200733 +200900 +200901 +200902 +200903 +200904 +200905 +200906 +200907 +200919 +200920 +200921 +200922 +200923 +200924 +200925 +200926 +200927 +200928 +200929 +200930 +200931 +200932 +200933 +200918 +200030 +200031 +201100 +201200 +201201 +201301 +201400 +201450 +201502 +201503 +201504 +201505 +201600 +201601 +201602 +201603 +201605 +201606 +201608 +201609 +201700 +201701 +201702 +201703 +201705 +201144 +200039 +202100 +200037 +201003 +200038 +200024 +200027 +200058 +202101 +202102 +202103 +202104 +202105 +202106 +202107 +202108 +202109 +202110 +202111 +202112 +202263 +202282 +202283 +202285 +202286 +202287 +202271 +202272 +202306 +201489 +201490 +201518 +201535 +201981 +202230 +202241 +202243 +202244 +202245 +202246 +202247 +202248 +202249 +202250 +202251 +202252 +202253 +202255 +202256 +202257 +202259 +202260 +202261 +202270 +202321 +202325 +202327 +202322 +202326 +202328 +201001 +207840 +207841 +207843 +209206 +201068 +202450 +202451 +202441 +202442 +202443 +202445 +202444 +202446 +202447 +202540 +202542 +202641 +203504 +203508 +203317 +203316 +203315 +205198 +201715 +200005 +200008 +200009 +201213 +201332 +203200 +203201 +203202 +203203 +203204 +203205 +203206 +203207 +203208 +203209 +203210 +203211 +203212 +203213 +203214 +203215 +203216 +203217 +203218 +203219 +203220 +203221 +203222 +204020 +204021 +204022 +200032 +200033 +204040 +204041 +204042 +204043 +204044 +204045 +204046 +204047 +204048 +204049 +204050 +204051 +204052 +204053 +204054 +204055 +201358 +202021 +204056 +204057 +204058 +200056 +200057 +200054 +200013 +200055 +204250 +204251 +204252 +204253 +204254 +204255 +204256 +204257 +204280 +204281 +204284 +204285 +204286 +204287 +204288 +201403 +201404 +201405 +204339 +202258 +204540 +204541 +204546 +204547 +204548 +204549 +204550 +204551 +204559 +204583 +204588 +204562 +200001 +201944 +204643 +204644 +204642 +201949 +204742 +204741 +204743 +205512 +201117 +201485 +201486 +201487 +201488 +204582 +205101 +205199 +205200 +205201 +205202 +205209 +205210 +205211 +205212 +205213 +205221 +205222 +205223 +205224 +205225 +205231 +205234 +205236 +205237 +205238 +206140 +206144 +206146 +206170 +206192 +201893 +203231 +206145 +200022 +200023 +209507 +209819 +209820 +209822 +209831 +206240 +206241 +206242 +206245 +206246 +206313 +206315 +206317 +206318 +206320 +206347 +206348 +206316 +201041 +201042 +200025 +206344 +206442 +206443 +200015 +200016 +206521 +206522 +206523 +206600 +206601 +206602 +206640 +206641 +206643 +206644 +206645 +206646 +206647 +200002 +202263 +207530 +207538 +207539 +208609 +200028 +200059 +201707 +203229 +205300 +205311 +207200 +207201 +207203 +207204 +207205 +207206 +207207 +207208 +207209 +207210 +207211 +207212 +207213 +207214 +207215 +207216 +207217 +207218 +207307 +207308 +207313 +207956 +207958 +207954 +202322 +207943 +207946 +207947 +207949 +207950 +207952 +207955 +207957 +207960 +207961 +207982 +209805 +209814 +209815 +209816 +207987 +207988 +209807 +207990 +207992 +207993 +207995 +200019 +200035 +208068 +200528 +208092 +202254 +202294 +203507 +208061 +208062 +208063 +208064 +208065 +208066 +208080 +208083 +208084 +208089 +208090 +208091 +208841 +208093 +208094 +208095 +208069 +208140 +208142 +208143 +208144 +208150 +208160 +208190 +200042 +208341 +208344 +200426 +200428 +200429 +200529 +200530 +208440 +208442 +208444 +208445 +208605 +208608 +208601 +208602 +208604 +208607 +208610 +208623 +209225 +208624 +208606 +201834 +201822 +201841 +201842 +201845 +208742 +208743 +208744 +208745 +208746 +208747 +201138 +201139 +201140 +201141 +201142 +208850 +208851 +208852 +208853 +208854 +208855 +208856 +208857 +208858 +208859 +208860 +208862 +208866 +208867 +208868 +208871 +208872 +208875 +208876 +208877 +208940 +208941 +208942 +208943 +208944 +208945 +208946 +208947 +209041 +209042 +203010 +203013 +203014 +203015 +203016 +203020 +203022 +203011 +203021 +190702 +203060 +203070 +190703 +203111 +203120 +203122 +201009 +201010 +201831 +203235 +204581 +205418 +205423 +206315 +207129 +207311 +208241 +208445 +208928 +209087 +209198 +209199 +209200 +209202 +209203 +209204 +209205 +209209 +209210 +209211 +209214 +209505 +209800 +201911 +204742 +201908 +201153 +201929 +202321 +202325 +202327 +202450 +202451 +203052 +208443 +208605 +209806 +209809 +209821 +209823 +209824 +209825 +209827 +209828 +209830 +209832 +209833 +209834 +209836 +209837 +209838 +201001 +201707 +203054 +205418 +205423 +205743 +206521 +206522 +206523 +208445 +209041 +209042 +209287 +209803 +209826 +209840 +209841 +209852 +208606 +209804 +201910 +209500 +209501 +209502 +201958 +209505 +201958 +209400 +201068 +202542 +206318 +200100 +201706 +201801 +201901 +203232 +203233 +203234 +206260 +206261 +206262 +206264 +207611 +208929 +201607 +201506 +201708 +201002 +201709 +201401 +201402 +207088 +205226 +201451 +206263 +207612 +201507 +200041 +200052 +202273 +202274 +202275 +202276 +202277 +202278 +202279 +202280 +202295 +209255 +202281 +202284 +202288 +202289 +202290 +202292 +202262 +202264 +202265 +202266 +202267 +202268 +202269 +202296 +202297 +202298 +202299 +202300 +202301 +202302 +202303 +205196 +205195 +201517 +202448 +202304 +202305 +200010 +200012 +200021 +200034 +201189 +207084 +201278 +201280 +203223 +203224 +203225 +203226 +203230 +203301 +203302 +203305 +203308 +203309 +203312 +203313 +203314 +203407 +203408 +203409 +203410 +203411 +203500 +203501 +203502 +203503 +203505 +203506 +203600 +203602 +203603 +203606 +203609 +203610 +203612 +203613 +203704 +203711 +203716 +203717 +203723 +203738 +203747 +203782 +203783 +203784 +203786 +203787 +203788 +203789 +203790 +203791 +203793 +203794 +203796 +205438 +205441 +206265 +206266 +206267 +206268 +206269 +207844 +207845 +208075 +208076 +208077 +208078 +208924 +208925 +208926 +208927 +201221 +201397 +200003 +200007 +201714 +201716 +201398 +201399 +203227 +206270 +206271 +206272 +203228 +203236 +209258 +200018 +200036 +200040 +203241 +203242 +207033 +200045 +200046 +200047 +200048 +200049 +200050 +200051 +205239 +205240 +205241 +205280 +205281 +205304 +205305 +205306 +205308 +205309 +205312 +205407 +205408 +205409 +205411 +205412 +205413 +205416 +205417 +205421 +205422 +205424 +205426 +205427 +205428 +205431 +205436 +205439 +205440 +205442 +205443 +205444 +205445 +205446 +205500 +205501 +205503 +205504 +205505 +205506 +205507 +205508 +205509 +205510 +205511 +205514 +205516 +205520 +205523 +205524 +205525 +205526 +205601 +205603 +205608 +205609 +205610 +205612 +205613 +205617 +205618 +205619 +205620 +205713 +205717 +205724 +205725 +205726 +205727 +205728 +205729 +205730 +205731 +205732 +205733 +205734 +205735 +205736 +205737 +205738 +205741 +205742 +205744 +205745 +205746 +205747 +205748 +205749 +205750 +205751 +206244 +207306 +207608 +207615 +207616 +207617 +207846 +208212 +208840 +209254 +209810 +209811 +209812 +209813 +205406 +205752 +205753 +205754 +205755 +205756 +205621 +205303 +205757 +201491 +201578 +205310 +205313 +205314 +205315 +205277 +205227 +205614 +205758 +200017 +201119 +200115 +200116 +200026 +200043 +205759 +205622 +205623 +205624 +205625 +205626 +205627 +205628 +201080 +201118 +207314 +207315 +207500 +207501 +207503 +207504 +207505 +207506 +207507 +207508 +207509 +207511 +207512 +207514 +207515 +207516 +207517 +207518 +207519 +207520 +207522 +207523 +207524 +207526 +207529 +207531 +207533 +207534 +207535 +207536 +207537 +207600 +207602 +207605 +207606 +207609 +207610 +207521 +207708 +207312 +207709 +205301 +200044 +208887 +208888 +208889 +208892 +208891 +204580 +201143 +208893 +209218 +209219 +209220 +209223 +209226 +209227 +209228 +209229 +209230 +209233 +209234 +209236 +209237 +209241 +209242 +209244 +209245 +209246 +209247 +209248 +209250 +209251 +209252 +209253 +209256 +209257 +209259 +209260 +209261 +209262 +209263 +209266 +209267 +209268 +209270 +209271 +209272 +209274 +209275 +209276 +209278 +209279 +209283 +209284 +209286 +209288 +209289 +209290 +209293 +209294 +209295 +209296 +209297 +209298 +209299 +209300 +209301 +209817 +201712 +209249 +200004 +200006 +209818 +205316 +201187 +201425 +201312 +209201 +209269 +201243 +201011 +201012 +200014 +200020 +209839 +209849 +209851 +209853 +209854 +200131 +209842 diff --git a/progress_XXI.txt b/progress_XXI.txt new file mode 100644 index 0000000..5060694 --- /dev/null +++ b/progress_XXI.txt @@ -0,0 +1,192 @@ +050004 +050008 +074170 +074171 +076000 +076001 +125017 +127022 +127511 +129008 +135040 +135060 +135110 +139160 +139270 +139950 +141129 +141209 +141374 +150104 +150105 +150110 +150160 +150161 +190559 +050008 +050004 +050008 +074170 +074171 +076000 +076001 +125017 +127022 +127511 +129008 +135040 +135060 +135110 +139160 +139270 +139950 +141129 +141209 +141374 +150104 +150105 +150110 +150160 +150161 +190559 +050008 +050008 +050008 +050004 +190800 +190801 +201911 +211400 +212000 +212002 +212003 +212004 +212006 +212007 +212010 +212011 +212012 +212013 +212014 +212015 +212017 +212018 +212019 +212020 +212021 +212022 +212023 +212025 +212026 +212027 +212060 +212109 +212111 +212112 +212114 +212118 +212121 +212125 +212163 +212400 +212405 +212406 +212408 +212410 +212412 +212413 +212414 +212416 +212418 +212419 +212501 +251210 +251211 +251212 +251213 +251215 +251216 +251217 +251218 +251219 +251220 +251221 +260081 +212103 +212104 +212105 +212402 +212403 +190020 +190021 +190022 +212037 +211028 +211043 +211099 +211104 +211110 +211122 +211132 +211402 +211403 +212009 +212029 +212030 +212033 +212035 +212063 +212064 +212098 +212099 +212123 +212129 +212130 +212133 +212160 +212162 +212300 +212415 +212500 +212038 +212110 +212024 +211430 +211431 +211432 +211433 +211436 +212028 +212134 +212435 +212425 +212136 +212039 +212135 +211138 +212426 +212138 +212040 +212427 +212041 +212428 +211054 +212115 +212165 +211060 +212140 +212043 +212044 +212142 +212143 +212429 +211434 +212144 +211418 +211401 +212108 +211144 +212417 +251214 +212126 +139161 diff --git a/vvz/src/scraper.py b/vvz/src/scraper.py index 3639085..4a98ae1 100644 --- a/vvz/src/scraper.py +++ b/vvz/src/scraper.py @@ -1,29 +1,81 @@ + import requests from bs4 import BeautifulSoup from urllib.parse import urljoin -from selenium import webdriver -from selenium.webdriver.chrome.options import Options import time , re , json - -def get_rendered_html(url, wait=3): - options = Options() - options.add_argument("--headless=new") - options.add_argument("--disable-gpu") - options.add_argument("--no-sandbox") - options.add_argument("--disable-dev-shm-usage") - - driver = webdriver.Chrome(options=options) +import traceback + +from appwrite.client import Client +from appwrite.services.databases import Databases +from datetime import datetime + +import os + +PROGRESS_FILE = "progress.txt" + +# Bereits gespeicherte Kurse laden +if os.path.exists(PROGRESS_FILE): + with open(PROGRESS_FILE, "r", encoding="utf-8") as f: + done_courses = set(line.strip() for line in f if line.strip()) +else: + done_courses = set() + +APPWRITE_ENDPOINT = "https://api-dev-app.asta-bochum.de/v1" +PROJECT_ID = "campus_app" +API_KEY = "standard_e4abd7e30c1178a41b4340fd40a30edcf0d2cedc5e5cb4cf4fc57762257435044b07d298e3c5139ad0df3ca6af08971350a2a6176a72782d9b67ddcdd7fc6d1093d5d9b72db1ed21390452bf7ec338b092fba2a8c3bb5bc2e92103518754dffe85e4bdf6f9ab38ecbcd46cd55ede2128ad1bd11e2e59cc028412ed63edcb1daa" +DATABASE_ID = "courses" +COLLECTION_ID = "" + +FACULTY_COLLECTIONS = { + "I.": "68ff4371002b37d0785c", # Evangelisch-Theologische FakultĂ€t + "II.": "69024b840015bdc729d8", # Katholisch-Theologische FakultĂ€t + "III.": "6907ab8900018027e6e0", # FakultĂ€t fĂŒr Philosophie und Erziehungswissenschaft + "IV.": "6907df0b000832908ded", # FakultĂ€t fĂŒr Geschichtswissenschaft + "V.": "690908e2000b559395bb", # FakultĂ€t fĂŒr Philologie + "VI.": "690938f100160232c270", # Juristische FakultĂ€t + "VIII.": "69093939003a6bb8c995", # FakultĂ€t fĂŒr Sozialwissenschaft + "VII.": "6909392b001c4f530c4a", # FakultĂ€t fĂŒr Wirtschaftswissenschaft + "IX.": "690939530003f03086f2", # FakultĂ€t fĂŒr Ostasienwissenschaft + "X.": "690939aa0031228ba3e2", # FakultĂ€t fĂŒr Sportwissenschaft + "XI.": "69093b05001a55bb235f", # FakultĂ€t fĂŒr Psychologie + "XII.": "69093b23001315a99b29", # FakultĂ€t fĂŒr Bau- und Umweltingenieurwissenschaften + "XIII.": "69093b5e000863a43a2c", # FakultĂ€t fĂŒr Maschinenbau + "XIV.": "69093b8b003b8a9295d4", # FakultĂ€t fĂŒr Elektrotechnik und Informationstechnik + "XV.": "69093bb200383849e0ad", # FakultĂ€t fĂŒr Mathematik + "XVI.": "69093bcb0003eff326d7", # FakultĂ€t fĂŒr Physik und Astronomie + "XVII.": "69093be4000d2adc74c9", # FakultĂ€t fĂŒr Geowissenschaften + "XIX.": "69093bfd002faa70dae0", # FakultĂ€t fĂŒr Biologie und Biotechnologie + "XX.": "69093c15001f6a1b1db5", # Medizinische FakultĂ€t + "XXI.": "69093c340021e62e4273", # FakultĂ€t fĂŒr Informatik + "XVIII.": "691b83300017df2f3c8e", # FakultĂ€t fĂŒr Chemie und Biochemie +} + + +# Appwrite Client einrichten +client = Client() +client.set_endpoint(APPWRITE_ENDPOINT) +client.set_project(PROJECT_ID) +client.set_key(API_KEY) + +db = Databases(client) + + +def fetch_html(url): try: - driver.get(url) - time.sleep(wait) - html = driver.page_source - finally: - driver.quit() - return html + r = requests.get(url, timeout=10) + r.raise_for_status() + return r.text + except Exception as e: + print(f"[WARN] Fehler beim Laden von {url}: {e}") + return "" + start_url = "https://vvz.ruhr-uni-bochum.de/campus/all/fields.asp?group=Vorlesungsverzeichnis&lang=de" + + + # FakultĂ€ten erkennen roman_re = re.compile(r'^([IVXLCDM]+)\.') def is_faculty(text: str) -> bool: @@ -37,186 +89,159 @@ def roman_order(name: str) -> int: return order.index(token) if token in order else 999 -def clean_lecturers(td): - # Zerlegt den Text an ZeilenumbrĂŒchen (z.B.
), entfernt leere EintrĂ€ge - if not td: - return "" - parts = [p.strip() for p in td.stripped_strings if p.strip()] - return " ; ".join(parts) +#als Array speichern +def clean_lecturers(cell): + names = [n.strip() for n in cell.stripped_strings if n.strip()] + return names - def list_courses(eventlist_url: str, module_title: str | None = None): - #print(f"[DEBUG] RENDER mit Selenium: {eventlist_url}") - html = get_rendered_html(eventlist_url) - #print(f"[DEBUG] LĂ€nge HTML: {len(html)}") - soup = BeautifulSoup(html, "html.parser") - - - - tables = soup.find_all("tbody", class_="tablecontent") - if not tables: - return [] courses = [] - - # ALLE Tabellen der Seite durchlaufen - for tbody in tables: - number_cells = tbody.find_all("td", id=re.compile("cas-table_EVENTLIST_COURSENUMBER_\\d+")) - for num_cell in number_cells: - tr = num_cell.find_parent("tr") - if not tr: - continue - - # Index aus ID holen - match = re.search(r"_(\d+)$", num_cell.get("id", "")) - if not match: - continue - idx = match.group(1) - - # Daten wie gewohnt auslesen - course_id = num_cell.get_text(" ", strip=True) - link_tag = num_cell.find("a") - detail_url = urljoin(eventlist_url, link_tag["href"]) if link_tag else None - - title_td = tr.find("td", id=f"cas-table_EVENTLIST_TITLE_{idx}") - lecturer_td = tr.find("td", id=f"cas-table_EVENTLIST_LECTURER_{idx}") - type_td = tr.find("td", id=f"cas-table_EVENTLIST_SWS_{idx}") - - title = title_td.get_text(" ", strip=True) if title_td else "" - lecturers = clean_lecturers(lecturer_td) - type_ = type_td.get_text(" ", strip=True) if type_td else "" - - details = scrape_course_details(detail_url) if detail_url else {"basisdaten": {}, "termine": []} - - courses.append({ - "module": module_title, - "course_id": course_id, - "title": title, - "lecturers": lecturers, - "type": type_, - "details_url": detail_url, - "basisdaten": details.get("basisdaten"), - "termine": details.get("termine") - }) + current_url = eventlist_url + + while True: + print(f"[INFO] Lade Kursseite: {current_url}") + + html = fetch_html(current_url) + soup = BeautifulSoup(html, "html.parser") + + tables = soup.find_all("tbody", class_="tablecontent") + if not tables: + break + + + for tbody in tables: + number_cells = tbody.find_all( + "td", + id=re.compile(r"cas-table_EVENTLIST_COURSENUMBER_\d+") + ) + + for num_cell in number_cells: + tr = num_cell.find_parent("tr") + if not tr: + continue + + match = re.search(r"_(\d+)$", num_cell.get("id", "")) + if not match: + continue + idx = match.group(1) + + course_id = ( + num_cell.find("a").get_text(strip=True) + if num_cell.find("a") + else num_cell.get_text(" ", strip=True) + ) + + link_tag = num_cell.find("a") + detail_url = urljoin(current_url, link_tag["href"]) if link_tag else None + + title_td = tr.find("td", id=f"cas-table_EVENTLIST_TITLE_{idx}") + lecturer_td = tr.find(id=f"cas-table_EVENTLIST_LECTURER_{idx}") + type_td = tr.find("td", id=f"cas-table_EVENTLIST_SWS_{idx}") + + title = title_td.get_text(" ", strip=True) if title_td else "" + lecturers = clean_lecturers(lecturer_td) + type_ = type_td.get_text(" ", strip=True) if type_td else "" + + details = scrape_course_details(detail_url) if detail_url else {"basisdaten": {}, "termine": []} + + courses.append({ + "module": module_title, + "course_id": course_id, + "title": title, + "lecturers": lecturers, + "type": type_, + "details_url": detail_url, + "basisdaten": details.get("basisdaten"), + "termine": details.get("termine") + }) + + + # Pagination – nĂ€chste Seite finden + + next_button = soup.find("a", {"title": "NĂ€chste Seite"}) + + if not next_button: + print("[DONE] Keine nĂ€chste Seite.") + break + + next_href = next_button.get("href") + if not next_href: + break + + next_url = urljoin(current_url, next_href) + + # WICHTIG: Endlosschleife verhindern (VVZ-BUG → page=7 wiederholt sich) + if next_url == current_url: + print("[STOP] Pagination wiederholt sich Ende erreicht.") + break + + # → nĂ€chste Seite + current_url = next_url return courses - - -def scrape_course_details(url): - try: - r = requests.get(url, timeout=10) # statt 30 - r.raise_for_status() - except Exception as e: - print(f"[WARN] Detailseite konnte nicht geladen werden: {url} ({e})") - return {"basisdaten": {}, "termine": []} - - -visited = set() - -""" def scrape_items(url, path=None): +def scrape_items(url, path=None): if path is None: path = [] - if url in visited: - return [] - visited.add(url) - - try: - html = get_rendered_html(url) - except Exception as e: - print(f"[WARN] Fehler bei {url}: {e}") + html = fetch_html(url) + if not html: return [] soup = BeautifulSoup(html, "html.parser") - # === Fall 1: Kursliste (eventlist.asp) === + + # FALL 1: eventlist.asp -> Kursliste scrapen + if "eventlist.asp" in url: - module_name = " > ".join(path) - print(f"\n Modul: {module_name}") - courses = list_courses(url, module_title=module_name) - for c in courses: - print(f" | {c['course_id']} | {c['title']} | {c['lecturers']} | {c['type']}") - if c.get("termine"): - for t in c["termine"]: - wochentag = t.get("wochentag", "") - start = t.get("start", "") - ende = t.get("ende", "") - raum = t.get("raum", "") - datum = t.get("datum", "") - print(f" {wochentag} {start}–{ende} @ {raum} ({datum})") - return courses - - # === Fall 2: Untermodul-Liste (subfields.asp oder fields.asp) === - tbody = soup.find("tbody", class_="tablecontent") - if not tbody: - return [] - results = [] - for a in tbody.find_all("a"): - text = a.get_text(strip=True) - href = a.get("href") or "" - if not text or not href: - continue - if href.startswith("#") or href.lower().startswith("javascript:"): - continue + # Modulname festlegen + if len(path) > 1: + module_name = path[-1] + else: + module_name = path[0] - full_url = urljoin(url, href) + print(f"\n Modul: {module_name}") - # Rekursion → gehe tiefer - results.extend(scrape_items(full_url, path + [text])) - time.sleep(0.2) + courses = list_courses(url, module_title=module_name) - return results """ + # Kurse anzeigen + speichern + if not courses: + print(f" [INFO] Keine Kurse gefunden in {module_name}") + else: + for c in courses: + course_id = c.get("course_id", "").strip() -def scrape_items(url, path=None): - if path is None: - path = [] + if course_id in done_courses: + print(f"[SKIP] Kurs {course_id} bereits gespeichert.") + continue - if url in visited: - return [] - visited.add(url) + print(f" | {c['course_id']} | {c['title']} | {c['lecturers']} | {c['type']}") + save_course_to_appwrite(c) - try: - html = get_rendered_html(url) - except Exception as e: - print(f"[WARN] Fehler bei {url}: {e}") - return [] + + result_list = [] + result_list.extend(courses) + return result_list - soup = BeautifulSoup(html, "html.parser") - # === Fall 1: Kursliste (eventlist.asp) === - if "eventlist.asp" in url: - module_name = " > ".join(path) - if len(path)==1: - return [] - print(f"\n Modul: {module_name}") - courses = list_courses(url, module_title=module_name) - - for c in courses: - print(f" | {c['course_id']} | {c['title']} | {c['lecturers']} | {c['type']}") - if c.get("termine"): - for t in c["termine"]: - wochentag = t.get("wochentag", "") - start = t.get("start", "") - ende = t.get("ende", "") - raum = t.get("raum", "") - datum = t.get("datum", "") - print(f" {wochentag} {start}–{ende} @ {raum} ({datum})") - return courses - - # === Fall 2: Untermodul-Liste (subfields.asp oder fields.asp) === + + #fields.asp / subfields.asp -> Unterseiten + tbody = soup.find("tbody", class_="tablecontent") if not tbody: return [] results = [] + for a in tbody.find_all("a"): text = a.get_text(strip=True) href = a.get("href") or "" + if not text or not href: continue if href.startswith("#") or href.lower().startswith("javascript:"): @@ -224,18 +249,21 @@ def scrape_items(url, path=None): full_url = urljoin(url, href) - # doppelte Namenswiederholung verhindern + # Pfad aktualisieren if path and path[-1] == text: - new_path = path # nicht nochmal anhĂ€ngen + new_path = path else: new_path = path + [text] - # Rekursion → gehe tiefer - results.extend(scrape_items(full_url, new_path)) + # Rekursion — Unterseite scrapen + sub_results = scrape_items(full_url, new_path) + results.extend(sub_results) + time.sleep(0.2) return results + @@ -244,7 +272,6 @@ def scrape_course_details(url): r.raise_for_status() soup = BeautifulSoup(r.text, "html.parser") - # --- Basisdaten --- base_data = {} for row in soup.select("div.templatecomponent.collapsible div.cas-info-row"): label = row.find("div", class_="cas-info-label") @@ -254,43 +281,111 @@ def scrape_course_details(url): val = value.get_text(" ", strip=True) base_data[key] = val - # Termine termine = [] + time_infos = [] + seen_dates = set() + table = soup.find("table", id="appointmentlist") if table: - # Oberste Terminzeile mit Wochentag, Uhrzeit, Raum - header_td = table.select_one("tbody.tablecontent tr td") - if header_td: - header_text = header_td.get_text(" ", strip=True) - - m = re.match(r"^([A-Za-z]+),\s*([\d:]+)\s*-\s*([\d:]+),\s*(.+)$", header_text) + tbody = table.find("tbody", class_="tablecontent") + current_header = None + + for tr in tbody.find_all("tr"): + text = tr.get_text(" ", strip=True) + if not text or "Termine" in text: # Störzeilen ignorieren + continue + + # Kopfzeile -> neuer Block + m = re.match(r"^([A-Za-zĂ„Ă–ĂœĂ€Ă¶ĂŒ]+),\s*(\d{1,2}:\d{2})\s*-\s*(\d{1,2}:\d{2}),\s*(.+)$", text) if m: - wochentag = m.group(1) - startzeit = m.group(2) - endzeit = m.group(3) - raum = m.group(4) - else: - wochentag = startzeit = endzeit = raum = "" - - # Einzeltermine → nach dem Header kommen weitere - date_rows = table.select("tbody.tablecontent tr")[1:] # ab 2. Zeile - for row in date_rows: - date_text = row.get_text(" ", strip=True) - if not date_text: + current_header = { + "weekday": m.group(1), + "start": m.group(2), + "end": m.group(3), + "room": m.group(4), + } + time_infos.append(f"{current_header['weekday']} {current_header['start']}-{current_header['end']} | {current_header['room']}") continue - termine.append({ - "datum": date_text, - "wochentag": wochentag, - "start": startzeit, - "ende": endzeit, - "raum": raum - }) + # Datumszeilen auslesen + dates = re.findall(r"\b\d{2}\.\d{2}\.\d{4}\b", text) + for date in dates: + if date not in seen_dates: # Dubletten vermeiden + seen_dates.add(date) + if current_header: + termine.append({ + "datum": date, + "wochentag": current_header["weekday"], + "start": current_header["start"], + "ende": current_header["end"], + "raum": current_header["room"] + }) + else: + termine.append({"datum": date}) + + # Termine nach Datum sortieren + termine.sort(key=lambda x: datetime.strptime(x["datum"], "%d.%m.%Y")) + + time_info = "; ".join(time_infos) return { "basisdaten": base_data, - "termine": termine + "termine": termine, + } + + + + +def save_course_to_appwrite(course,COLLECTION_ID): + + lecturers_list = course.get("lecturers", []) + if isinstance(lecturers_list, str): + lecturers_list = [lecturers_list] + + termine_raw = course.get("termine", []) + termine_list = [] + + for t in termine_raw: + if isinstance(t, dict): + # Formatieren in String + w = t.get("wochentag", "") + d = t.get("datum", "") + s = t.get("start", "") + e = t.get("ende", "") + r = t.get("raum", "") + termine_list.append(f"{w} {d} {s}-{e} | {r}".strip()) + else: + termine_list.append(str(t)) + + payload = { + "course_id": course.get("course_id", ""), + "title": course.get("title", ""), + "module": course.get("module", ""), + "lecturers": lecturers_list, + "type": course.get("type", ""), + "termine": termine_list, + "details_url": course.get("details_url", "") + + } + print("\n[UPLOAD] →", payload["course_id"], payload["title"], payload["termine"]) + + try: + res = db.create_document( + database_id=DATABASE_ID, + collection_id=COLLECTION_ID, + document_id="unique()", + data=payload + ) + print(f" Gespeichert: {res['$id']} - {payload['title']}") + + # Fortschritt dauerhaft speichern + course_id = payload["course_id"] + with open(PROGRESS_FILE, "a", encoding="utf-8") as f: + f.write(course_id + "\n") + done_courses.add(course_id) + except Exception as e: + print(f"Fehler beim Speichern: {e}") @@ -313,23 +408,56 @@ def scrape_course_details(url): faculties.append(key) faculties.sort(key=lambda x: roman_order(x[0])) -faculties = faculties[:1] # zum Testen nur die erste FakultĂ€t +#faculties = faculties[0:1] all_courses = [] for fac_name, fac_url in faculties: print(f"\n====== {fac_name} ======") + + # 1ïžâƒŁ FakultĂ€tskĂŒrzel extrahieren (z. B. "XIV.") + fac_short = fac_name.split()[0] # NICHT .replace(".") !! + + # 2ïžâƒŁ Automatisch die richtige Collection-ID wĂ€hlen + if fac_short not in FACULTY_COLLECTIONS: + print("[ERROR] Unbekannte FakultĂ€t:", fac_short) + continue + + COLLECTION_ID = FACULTY_COLLECTIONS[fac_short] + print("[INFO] → Verwende Collection:", COLLECTION_ID) + + # 3ïžâƒŁ Progress-Datei pro FakultĂ€t + #PROGRESS_FILE = f"progress_{fac_short}.txt" + PROGRESS_FILE = f"progress_{fac_short.replace('.', '')}.txt" + + + if os.path.exists(PROGRESS_FILE): + with open(PROGRESS_FILE, "r", encoding="utf-8") as f: + done_courses = set(line.strip() for line in f if line.strip()) + else: + done_courses = set() + + # 4ïžâƒŁ Jetzt scrapen courses = scrape_items(fac_url, [fac_name]) all_courses.extend(courses) - -# hier nur zum testen der ersten Ebene also nur name der FakulitĂ€ten mit dennen Links -"""print("\n====== FakultĂ€ten (Testlauf) ======") -for i, (name, url) in enumerate(faculties): - print(f"{i+1:02d}. {name} → {url}")""" # JSON-Ausgabe print(json.dumps(all_courses, indent=2, ensure_ascii=False)) +for course in all_courses: + course_id = course.get("course_id", "") + if course_id in done_courses: + print(f"[SKIP] {course_id} bereits gespeichert.") + continue + + save_course_to_appwrite(course, COLLECTION_ID) + + + + + + + From 5eae57dd0d2522efc5642d950907786f0648e459 Mon Sep 17 00:00:00 2001 From: Tasnim2001 Date: Wed, 3 Dec 2025 10:20:28 +0100 Subject: [PATCH 4/4] scraping updated --- vvz/src/scraper.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/vvz/src/scraper.py b/vvz/src/scraper.py index 4a98ae1..3f138cb 100644 --- a/vvz/src/scraper.py +++ b/vvz/src/scraper.py @@ -173,12 +173,12 @@ def list_courses(eventlist_url: str, module_title: str | None = None): next_url = urljoin(current_url, next_href) - # WICHTIG: Endlosschleife verhindern (VVZ-BUG → page=7 wiederholt sich) + if next_url == current_url: print("[STOP] Pagination wiederholt sich Ende erreicht.") break - # → nĂ€chste Seite + # nĂ€chste Seite current_url = next_url return courses @@ -255,7 +255,7 @@ def scrape_items(url, path=None): else: new_path = path + [text] - # Rekursion — Unterseite scrapen + # Rekursion , Unterseite scrapen sub_results = scrape_items(full_url, new_path) results.extend(sub_results) @@ -414,10 +414,10 @@ def save_course_to_appwrite(course,COLLECTION_ID): for fac_name, fac_url in faculties: print(f"\n====== {fac_name} ======") - # 1ïžâƒŁ FakultĂ€tskĂŒrzel extrahieren (z. B. "XIV.") + # FakultĂ€tskĂŒrzel extrahieren (z. B. "XIV.") fac_short = fac_name.split()[0] # NICHT .replace(".") !! - # 2ïžâƒŁ Automatisch die richtige Collection-ID wĂ€hlen + # Automatisch die richtige Collection-ID wĂ€hlen if fac_short not in FACULTY_COLLECTIONS: print("[ERROR] Unbekannte FakultĂ€t:", fac_short) continue @@ -425,7 +425,7 @@ def save_course_to_appwrite(course,COLLECTION_ID): COLLECTION_ID = FACULTY_COLLECTIONS[fac_short] print("[INFO] → Verwende Collection:", COLLECTION_ID) - # 3ïžâƒŁ Progress-Datei pro FakultĂ€t + # Progress-Datei pro FakultĂ€t #PROGRESS_FILE = f"progress_{fac_short}.txt" PROGRESS_FILE = f"progress_{fac_short.replace('.', '')}.txt" @@ -436,7 +436,7 @@ def save_course_to_appwrite(course,COLLECTION_ID): else: done_courses = set() - # 4ïžâƒŁ Jetzt scrapen + # Jetzt scrapen courses = scrape_items(fac_url, [fac_name]) all_courses.extend(courses)