RMV API auslesen
Um Vorhersagen über Zugverspätungen machen zu können, werden zunächst Daten gesammelt. Der Rhein-Main-Verkehrsverbund bietet eine offene API an. Dabei wird eine Access ID benötigt. Dafür ist eine Anmeldung erforderlich, über die Nutzung muss Auskunft erteilt werden usw.
Laut der Nutzungsbedingungen dürfen dabei maximal 600 Einzelabfragen pro Stunde und bis zu 5000 Einzelabfragen pro Tag vorgenommen werden.

RMV Open Data
https://opendata.rmv.de/site/start.html
Beispielsweise werden die Abfahrtszeiten von Groß-Gerau Dornberg nach Frankfurt Main Hauptbahnhof wie folgt abgerufen:
Man erhält z.B. folgende JSON-Daten (gekürzt):
1 2 3 ... 231 232 ... 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 ... 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 ... 775 ... 788 |
{
"Departure": [
{
|
Listing 1: Beispiel einer JSON-Antwort der RMV Open Api
CollectDelays.py
Mit dem folgenden Script CollectDelays.py werden die Daten zunächst abgerufen und in einer MongoDB-Datenbank gespeichert:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
# RMV Open Data API # https://opendata.rmv.de/site/start.html # Get Client ID and API key from the Developer Console import settings import urllib.request import json import os from pymongo import MongoClient from datetime import datetime import csv client = MongoClient(settings.CONNECTION_STRING) # get MongoDB Client db = client['RMV-Pull-Stop'] # create mono db if not exists collection = db["GG-FFM"] # create collection if not exists #collection.drop() # get pull-stop data from RMV API def pull_stop_data(stopID: str, direction: str): source_url = f"https://www.rmv.de/hapi/departureBoard?id={stopID}&direction={direction}&accessId={settings.API_TOKEN}&format=json" with urllib.request.urlopen(source_url) as url: data: str = json.loads(url.read().decode()) # write to file dir = os.path.dirname(__file__) filename = os.path.join(dir, "data/departureBoard.json") f = open(filename, "w") f.write(json.dumps(data, indent = 4, sort_keys=True)) f.close() #print(json.dumps(data, indent = 4, sort_keys=True)) stopData = [] for departure in data["Departure"]: # collect some data dictionary = {} dictionary['stop'] = departure['stop'] dictionary['direction'] = departure['direction'] dictionary['date'] = departure['date'] dictionary['time'] = departure['time'] dictionary['name'] = departure['name'] if 'rtDate' in departure: # date of delayed arrival dictionary['rtDate'] = departure['rtDate'] if 'rtTime' in departure: # time of delayed arrival dictionary['rtTime'] = departure['rtTime'] if 'Occupancy' in departure: # if info 'Belegung' available raw = departure['Occupancy'][0]['raw'] key = "text.occup.jny.max." + str(raw) for n in departure['Notes']['Note']: if n['key'] == key: #print(n['value']) dictionary['occupancy'] = n['value'] stopData.append(dictionary) return stopData # Save data in mongo db for direction in settings.directions: # get some departure data per direction pullStopDir = pull_stop_data(settings.stopID, direction) for psd in pullStopDir: # insert departure data in document if departure times not exist collection.update_one( { 'date' : psd.get("date"), 'time' : psd.get("time") }, { '$setOnInsert': psd }, upsert = True ) # update delay data in existing document if changed collection.update_one( { 'date' : psd.get("date"), 'time' : psd.get("time") }, { '$set': { 'rtDate': psd.get("rtDate"), 'rtTime': psd.get("rtTime") } }, upsert = True ) |
Listing 2: Aufruf der RMV API und speichern und aktualisieren der JSON-Daten in MongoDB
Die aktuelle Software findet sich auf GitHub:
https://github.com/ateachment/RMV
Eine aktuelle JSON-Antwort für den Bahnhof Groß-Gerau Dornberg in die Richtungen Frankfurt (Main) Hauptbahnhof) wird hier bereitgestellt:
https://h.eick-at.de/downloads/departureBoard.json
(Aktualisierung alle 10 Minuten)
MongoDB
MongoDB ist ein sogenanntes NoSQL-Datenbankmanagmentsystem (Not only SQL), das es erlaubt, die JSON-Daten der API (ohne Strukturzwang) zu speichern bzw. diese sich ändernden JSON-Daten einfach zu aktualisieren,
Z.B. werden so folgende Dokumente in der MongoDB gespeichert und gegebenenfalls aktualisiert:
{
'_id': ObjectId('6378d945a703cf4edb35cad8'),
'date': '2022-11-19',
'time': '12:09:00',
'direction': 'Frankfurt (Main) Hauptbahnhof',
'name': 'S7',
'occupancy': 'Geringe Belegung',
'rtDate': '2022-11-19',
'rtTime': '12:10:00',
'stop': 'Groß-Gerau Dornberg Bahnhof'
}
Dabei wird _id von MongoDB hinzugefügt.
CSV-Format
Im CSV-Format (comma-separated values) können die Daten dann durch Datenanalyse oder KI-Tools weiterverarbeitet werden. Daher werden im weiteren Verlauf von CollectDelays.py die Daten dann aus der MongoDB gelesen, verarbeitet und entsprechend gespeichert:
94 |
# write to csv file dir = os.path.dirname(__file__) filename = os.path.join(dir, "data/delays.csv") f = open(filename, 'w', newline='') writer = csv.writer(f) fields = ['datetime', 'delay', 'name', 'occupancy'] writer.writerow(fields) query = { } doc = collection.find(query,{'_id':False}) # exlude _id from result dict (save memory) for d in doc: datetimePlanned = datetime.strptime(d['date']+d['time'],"%Y-%m-%d%H:%M:%S") if 'rtDate' not in d: d['rtDate'] = d['date'] if d['rtDate'] == None: d['rtDate'] = d['date'] if d['rtTime'] == None: d['rtTime'] = d['time'] if 'name' not in d: d['name'] = d['product'] if 'occupancy' not in d: d['occupancy'] = "-" datetimeDelayed = datetime.strptime(d['rtDate']+d['rtTime'],"%Y-%m-%d%H:%M:%S") delay = datetimeDelayed - datetimePlanned print(datetimeDelayed.isoformat() + " - " + datetimePlanned.isoformat() + " = " + str(delay)) data = [datetimePlanned.isoformat(),str(delay), d['name'], d['occupancy']] writer.writerow(data) f.close() |
Listing 3: JSON-Daten aus MongoDB in das CSV-Format überführen
Eine Zeile sieht dann z.B. so aus:
2022-11-19T12:09:00,0:01:00,S7,Geringe Belegung
Die aktuelle CSV-Datei mit Verspätungsdaten wird hier bereitgestellt:
https://h.eick-at.de/downloads/delays.csv
(Aktualisierung alle 10 Minuten)
Weitere Quellen:
https://www.mongodbtutorial.org/mongodb-crud/mongodb-updateone/ (19.11.2022)