import requests from pprint import pprint OVERPASS_URL = "https://overpass-api.de/api/interpreter" BERGBAHN_QUERY = """ [out:json][timeout:3][maxsize:500000]; ( node["aerialway"="station"]({bbox}); way["aerialway"="station"]({bbox}); node["railway"="funicular"]({bbox}); way["railway"="funicular"]({bbox}); node["railway"="station"]["funicular"="yes"]({bbox}); ); out center body; """ def fetch_bergbahnen(bbox: tuple) -> dict: """ Fragt die Overpass API nach Bergbahnen in der angegebenen Bounding Box ab. Sendet einen HTTP-POST-Request an die Overpass API und gibt die geparste JSON-Antwort zurück. Die Funktion prüft den HTTP-Status-Code, bevor sie versucht die Antwort als JSON zu parsen. Args: bbox (tuple): Bounding Box als 4-Tuple in Dezimalgrad: (south, west, north, east) Beispiel Davos: (46.72, 9.70, 46.92, 10.00) Beispiel Schweiz: (45.8, 5.9, 47.8, 10.5) Returns: dict: Geparste JSON-Antwort der Overpass API. Die Antwort enthält unter dem Schlüssel "elements" eine Liste von OSM-Objekten (nodes und ways) mit ihren Tags und Koordinaten. Beispiel: { "elements": [ { "type": "node", "id": 123456, "lat": 46.8, "lon": 9.8, "tags": {"aerialway": "station", "name": "Jakobshorn"} }, ... ] } Raises: RuntimeError: Wenn die API einen HTTP-Fehlercode zurückgibt (z.B. 429 Too Many Requests, 504 Gateway Timeout). RuntimeError: Wenn der Response-Body kein gültiges JSON enthält (z.B. bei leerem Body nach einem Server-Timeout). requests.Timeout: Wenn die API nicht innerhalb einer bestimmten Zeit (timeout) antwortet. """ bbox_str = ",".join(map(str, bbox)) query = BERGBAHN_QUERY.format(bbox=bbox_str) resp = requests.post( OVERPASS_URL, data={"data": query}, timeout=10, # clientseitiges timeout ist nicht serverseitiges timeout (das ist im query selbst auf z.B. 3 Sekunden gestellt) headers={"User-Agent": "GeoService/1.0 (poi-generator)"}, ) if resp.status_code != 200: raise RuntimeError( f"Overpass API Fehler: {resp.status_code}\n{resp.text}" ) try: data = resp.json() except requests.exceptions.JSONDecodeError: raise RuntimeError( f"Antwort ist kein gültiges JSON:\n{resp.text[:200]}" ) # HTTP 200 bedeutet nicht immer Erfolg — Overpass meldet Fehler im Body unter 'remark'! if "remark" in data: raise RuntimeError( f"Overpass Query-Fehler: {data['remark']}" ) return data if __name__ == "__main__": bbox = (46.72, 9.70, 46.92, 10.00) # bbox = (45.8, 5.9, 47.8, 10.5) result = fetch_bergbahnen(bbox) pprint(result) # Was ist passiert? # Wir haben verschiedene Fehler (verschiedene Ebenen) abgefangen: # Ebene 1 — Netzwerk: requests.Timeout → Client wartet vergebens # Ebene 2 — HTTP: status_code != 200 → Server meldet Fehler # Ebene 3 — Fachlich: "remark" im JSON-Body → Query lief, aber mit Fehler # TASK: # * verlagert als nächstes die Logik von 'fetch_bergbahnen' in ein eigenes Modul 'overpass.py' aus. # * nennt die Funktion allgemeiner 'fetch_overpass' (anstelle fetch_bergbahnen) -> somit würde es Sinn # machen, wenn wir den Query der Funktion als Argument mitgeben könnten (ist genereller). # * Erstellt in diesem main.py eine eigene 'main-Funktion', welche nur die Hauptlogik beinhalten und somit 'fetch_overpass' # importiert und aufruft.