Files

4.0 KiB
Raw Permalink Blame History

name, description, version, author, platforms, models, related_skills, license
name description version author platforms models related_skills license
gtfs-timetable-routing Use when: echte Zugfahrzeiten (Nahverkehr) braucht. 1.0.0 mehlzoerwer
linux
default
mimo-v2-flash
web-hosting-deployment
pocketbase-deployment
MIT

🚂 GTFS-Timetable-Routing — echte Zugverbindungen aus Fahrplandaten

When to Use

Nutze diesen Skill, wenn echte, verlässliche Nahverkehrs-Fahrzeiten (von→nach per Regional-/S-Bahn, kein ICE) benötigt werden — z.B. für eine Zugverbindungs-Webseite, Produkt-Planung oder Fahrzeit-Angaben. Kein Luftlinien-Raten, kein Erfinden von Zeiten.

Anlass (Nutzer-Korrektur): Die Urlaub-Webseite (urlaub.perfekt-ohne-en.de) zeigte Fahrzeiten aus Luftlinien-Schätzung — komplett falsch (2. Ebene halbe Zeit, bis 3× daneben). Der Nutzer verlangte reale Zeiten (max ~1h daneben). Lösung: GTFS-Fahrplandatei lokal verarbeiten.

Die harte Wahrheit: öffentliche Fahrplan-APIs sind zu

Bevor Zeit mit Scraping/APIs verbrannt wird — getestet (2026-08), alle scheitern programmatisch:

Quelle Ergebnis
DB-API / bahn.de Bot-Block / OPS_BLOCKED / 403
api.transport.rest DNS/000
transport.rest v6 503
reiseauskunft.de toter Pfad
VRR-EFA (efa.vrr.de V2) 405 (nginx blockt GET+POST)
WebSearch-Tool nicht konfiguriert (Firecrawl-Key fehlt)

Verlässlicher Weg = eine GTFS-Datei (Regional+S-Bahn, kein ICE ist ideal: genau Deutschlandticket-Nahverkehr). Datei lokal in SQLite → Dijkstra-Router → echte Zeiten. Kosten 0 $, schnell (<1s/Verbindung nach Build).

Arbeitsablauf

  1. GTFS-Datei beschaffen. Nutzer liefert .zip (z.B. r.und.s.bahnen.zip, „ohne ICE/IC"). Enthält stops.txt, trips.txt, stop_times.txt, calendar*.txt, routes.txt. Aus /user-cache-Dokument-Pfad kopieren.
  2. Extrahieren + in SQLite laden (scripts/build_gtfs_db.py). 3 Tabellen: stops(stop_id,stop_name,lat,lon), trips(trip_id,route_id,service_id), st(stop_id,trip_id,seq,arr,dep) + Indizes auf st(stop_id), st(trip_id), st(trip_id,seq).
  3. Router bauen/ausführen (scripts/gtfs_suche.py, zeitbasierter Dijkstra): vorladen deps_by_stop und stops_by_trip, dann Dijkstra mit dist[stop]=beste Ankunft + Ziel-Abbruch.
  4. Verifizieren gegen eine bekannte echte Strecke (z.B. Aachen Hbf→Köln Hbf ≈ 1h 12min, 1 Umstieg). Wenn plausibel → alle Ziele neu berechnen.
  5. Website/DB aktualisieren mit den echten Zeiten (nicht erfinden).

⚠️ Kritische Pitfalls (alle beim echten Lauf getroffen)

  1. stops.txt-Spaltenreihenfolge ist stop_name, parent_station, stop_id, stop_lat, stop_lon, ... — stop_id ist Spalte 2, NICHT Spalte 0; parent_station ist Spalte 1 (echte Gruppen-ID). Bei falschem Mapping kommen Stops mit leeren IDs / falschen Namen.
  2. trips.txt-Header ist route_id, service_id, trip_id — trip_id ist Spalte 2. Import NICHT an Spalte 0 hängen.
  3. Bahnhof hat mehrere stop_ids (z.B. Köln Hbf = 222681 UND 452576), aber nur eine ist aktiv in stop_times. stops.txt-ID ≠ notwendigerweise stop_times-ID. → Beim Auflösen: die ID wählen, die COUNT(*) IN st > 0 hat.
  4. st-Tabelle kann mehr eindeutige trips enthalten als trips.txt (110k vs 964 war ok — st ist Wahrheit). Zähler-Ausgaben prüfen, nicht dem trips.txt-Import trauen.
  5. Zeit-Parser: HH:MM und HH:MM:SS tolerant parsen (split(":"), defaults).
  6. Dijkstra-Effizienz: Bei vielen Trips (110k) explodiert naive Expansion → nutze dist[stop] + Ziel-Abbruch + visited. Erst nach Effizienz-Fix: Aachen→Köln in Sekunden statt Hänger.

Bauen

Die Referenzdatei references/gtfs-build-notes.md enthält Schema + Dijkstra-Kern + SQL. Die Skripte scripts/build_gtfs_db.py und scripts/gtfs_suche.py sind direkt ausführbar (Fahrzeit von→nach, <von_stop_id> <nach_stop_id> [HH:MM]).

Verwandt: Bei PocketBase als Ziel echte Zeiten in DB schreiben → pocketbase-deployment (Schema + Filter-Quirks). Bei Web-Frontend-Einbindung → web-hosting-deployment.