Skip to main content

Train connections with Python

··2 mins
Update 2025-10-28 Updated to https://v6.db.transport.rest

I’m commuting to my office by train a few times a week and I always wanted to have something like this: https://callingallstations.co.uk/2016/08/25/departureboard/

Since I’m all thumbs I thought I’d try solving this with software first. My reasaerch yielded a few public APIs, but none had the information I was looking for… until I stumbled accross this:

https://v6.db.transport.rest/

A little bit later I had this prototype

import requests

BASE_URL = "https://v6.db.transport.rest"
HEADERS = {"user-agent": "python-requests/2.23.0 +https://gist.github.com/redtoad/0e1aa4e42390a18d09e870843a8ec7db"}

data = requests.get(BASE_URL + "/stations?query=Augsburg", headers=HEADERS).json()
for _, item in data.items():
    print("{id} {name}".format(**item))

data = requests.get(BASE_URL + "/stations?query=Hirschgarten", headers=HEADERS).json()
for _, item in data.items():
    print("{id} {name}".format(**item))

which lists all relevant statino IDs for me.

8000013 Augsburg Hbf
8000661 Augsburg-Hochzoll
8000662 Augsburg-Oberhausen
8089065 Hirschgarten
8004179 München-Hirschgarten

With this we can query for journeys:

import dateutil.parser
import requests

BASE_URL = "https://v6.db.transport.rest"

AUG = "8000013"
MUC = "8004179"

data = requests.get(BASE_URL + "/journeys?from={start}&to={stop}".format(start=MUC, stop=AUG), headers=HEADERS)
for journey in data.json().get("journeys", []):

    if journey["type"] != "journey":
        continue

    legs = journey["legs"]
    departure = (legs[0]["departure"], (legs[0].get("departureDelay", 0) or 0)//60)  # delay in seconds
    arrival = (legs[-1]["arrival"], (legs[-1].get("arrivalDelay", 0) or 0)//60)  # delay in seconds
    products = " > ".join(leg["line"]["name"] for leg in legs if "line" in leg)

    print("{0.hour:02d}:{0.minute:02d} +{1} --> {2.hour:02d}:{2.minute:02d} +{3}  {4}".format(
        dateutil.parser.parse(departure[0]).time(),
        departure[1],
        dateutil.parser.parse(arrival[0]).time(),
        arrival[1],
        products))

Obviously this is quite ugly but might be a nice strting point.