In den vergangenen Wochen entwickelte ich eine App für den Vertretungsplan meiner Schule.

Anmerkung: Alle Daten und Namen, die in den Screenshots zu sehen sind, sind rein fiktiv. Jede Ähnlichkeit zu echten Daten oder Personen, lebendig oder verstorben, ist purer Zufall. Die Screenshots enthalten keine Daten des echten Online-Vertretungsplans und verstoßen dadurch nicht gegen dessen Nutzungsbedingungen.

Bisherige Situation

Vor der Entwicklung der Android-app konnten Schüler meiner Schule den Vertretungsplan wie folgt einsehen:

  • im Schulgebäude
  • online (momentan beschränkt auf Schüler der Oberstufe)

Der Online-Vertretungsplan wurde in diesem Schuljahr eingeführt und ermöglicht es Schülern, den Vertretungsplan »gemütlich« nach der Schule oder vor Schulbeginn um ca. 7:30 Uhr einzusehen.

Kleiner Bildschirm

Abbildung 1. Kleiner Bildschirm

Auch wenn dies ein nettes Feature ist, hat es seine Probleme:

  • Hässliche Nutzeroberfläche
  • Schlechte Lesbarkeit durch mangelhafte Wahl ein Kontrast zwischen Text und Hintergrund
  • Keine mobile Oberfläche, und eine schlechte Nutzererfahrung für mobile Nutzer (zu viel Scrolling, kaum erreichbare Steuerelemente)

Die Idee

Die grundlegende Idee war es, eine App zu entwickeln, die dem Nutzer nur die für ihn relevanten Daten präsentiert. Momentan würde das bedeuten, dass man nur die Kurse der aktuellen Klassenstufe zu Gesicht bekommt.

Android-App

Abbildung 2. Android-App

Um es übersichtlich zu halten, soll der Nutzer zunächst nur die relevantesten Daten sehen, und weitere Informationen beim Interagieren mit dem jeweiligen Eintrag erhalten.

Das Problem

In der Theorie war das Abrufen der notwendigen Daten der einfachste Teil. Ich würde die zuständige AG (»Arbeitsgemeinschaft«) kontaktieren und darum bitten, entweder Zugriff zum Quellcode zu erlangen, um eine maschinenlesbare API selbst zu implementieren, oder sie eine solche API implementieren zu lassen. Jedoch habe ich nicht einmal eine Antwort auf meine Anfrage erhalten.

Also war es doch nicht so einfach wie erwartet. Eine Zusammenarbeit war nicht vorhanden und die Kommunikation war spärlich. Um meinen letzten Stolz zu wahren, entschied ich mich, das Problem auf eigene Faust zu lösen, ohne deren Unterstützung.

Die Lösung

Glücklicherweise bin ich mehr oder weniger erfahren im Web Scraping, aufgrund vergangener Aufgaben, die das Sammeln von Daten aus verschiedenen Webseiten umfassten. Das hier war nichts anderes. Die Idee ist, dass man die Webseite so ausliest und nutzt, als wäre das Programm selbst ein Nutzer. In diesem Fall habe ich mit der Jsoup-Bibliothek und CSS-Selektoren gearbeitet. Jsoup beschreibt sich selbst als »praktische API zum Extrahieren und Manipulieren von Daten«. Natürlich verarbeiten Nutzer Webseiten nichts mittels CSS-Selektoren, aber es ist ein Anfang.

Struktur

Abbildung 3. Struktur

Die Schritte zum Sammeln der Vertretungsplandaten sind:

  1. Lade den HTML-Code für den Vertretungsplan, den wir abrufen wollen (/heute für heute und /morgen für morgen)
  2. Verarbeite den Code mittels Jsoup
  3. Frage alle Tabellenzeilen durch diesen CSS-Selektor ab: #vertretungsplan tr
  4. Für jede Zeile: rufe alle td-Elemente ab, verarbeite ihre Daten und speise sie in eine Liste ein

Nachdem alle Daten verarbeitet wurden können sie wie vorgesehen dargestellt werden. Ein weiteres Problem war die Authentifizierung. Der Online-Vertretungsplan nutzt PHP-Session-Ids und Cookies für die Authentifizierung. Der Authentifizierungsablauf sieht wie folgt aus: Gebe deine Daten in das Anmeldeformular ein, führe eine POST-Request zur Indexseite aus um deine Session-ID für zukünftige Anfragen zu authentisieren, und erhalte ab dann Daten von /heute und /morgen. Aber das würde bedeuten, dass man jedes Mal, wenn ein erneuter Login erforderlich ist, eine Authentifizierungsabfrage ausführen muss. Und auch bei nicht authentisierten Anfragen müsste ich jedes die zurückgegebene Seite auf Fehler prüfen, da diese wahnsinnige Anwendung keinerlei Gebrauch von HTTP-Status-Codes macht. Der HTML-Code ist ebenfalls fehlerhaft: HTML-IDs müssen laut Standard einzigartig sein, werden aber im Online-Vertretungsplan mehrfach auf der gleichen Seite genutzt. Rechtschreibfehler sind ebenfalls mehrfach vorhanden.

Wie ich später herausgefunden habe, ist es egal, an welche Seite die POST-Request zur Authentifizierung gesendet wird. Um also Traffic zu sparen sende ich die Authentifizierungsinformationen mit jeder Anfrage an /heute und /morgen. Auf den ersten Blick mag dies wie ein Sicherheitsrisiko erscheinen, aber alle Anfragen werden mittels TLS (Transport Layer Security) übertragen und mit den Accounts sind keinerlei sensitive Daten verknüpft.

Zukünftige Pläne

Das größte geplante Feature sind Benachrichtigungen basierend auf einer nutzerdefinierten Liste von Kursen. In einem festen Intervall soll die App die Vertretungsplandaten erneut laden, eine Menge an Änderungen generieren und anhand dieser Benachrichtigungen zu den eingestellten Kursen anzeigen. Ich bin mir noch nicht sicher, ob ich ein Cloud-Sync-Feature einbauen werde, da die App momentan vollständig ohne einen serverseitigen Teil auskommt – abgesehen vom bereits vorhandenen Online-Vertretungsplan.

Open Source

Der vollständige Quellcode der App steht auf GitHub unter der BSD-2-Klausel-Lizenz zur Verfügung.