Quellen ohne Last-Modified (Wiener Linien): täglich laden und am Inhalt erkennen, ob es Neues gibt

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X48pE4bzjHej8w9HyZXCjb
This commit is contained in:
Claude
2026-10-23 11:29:06 +02:00
parent ef67df6e00
commit f8fa1918cd
2 changed files with 13 additions and 4 deletions
+1
View File
@@ -77,6 +77,7 @@ SOURCES = {
}, },
"at_wl": { # Wiener Linien (Tram, U-Bahn, Badner Bahn), CC BY 4.0 "at_wl": { # Wiener Linien (Tram, U-Bahn, Badner Bahn), CC BY 4.0
"country": "at", "country": "at",
"check_hours": 24, # Server nennt kein Datum: 1x täglich laden (~100 MB) und Inhalt vergleichen
"gtfs_url": "http://www.wienerlinien.at/ogd_realtime/doku/ogd/gtfs/gtfs.zip", "gtfs_url": "http://www.wienerlinien.at/ogd_realtime/doku/ogd/gtfs/gtfs.zip",
"rt_url": "", "rt_key": "", "needs_key": False, "rt_interval": 60, "rt_url": "", "rt_key": "", "needs_key": False, "rt_interval": 60,
}, },
+12 -4
View File
@@ -8,6 +8,7 @@ und macht für eine Quelle nichts, solange dort kein neuer Fahrplan veröffentli
""" """
import argparse import argparse
import csv import csv
import hashlib
import datetime as dt import datetime as dt
import io import io
import json import json
@@ -69,14 +70,15 @@ def download(url: str, dest: Path) -> None:
def remote_id(src: str, url: str) -> tuple[str, str | None]: def remote_id(src: str, url: str) -> tuple[str, str | None]:
"""Kennung der aktuell veröffentlichten Datei, ohne sie herunterzuladen: (Name, Datum JJJJMMTT oder None).""" """Kennung der aktuell veröffentlichten Datei, ohne sie herunterzuladen: (Name, Datum JJJJMMTT oder None).
Name None: der Server sagt nichts (Wiener Linien) – dann entscheidet der Inhalt nach dem Download."""
if src == "ch": if src == "ch":
return latest_gtfs_name(url), None return latest_gtfs_name(url), None
r = httpx.head(url, follow_redirects=True, timeout=60, headers={"User-Agent": C.USER_AGENT}) r = httpx.head(url, follow_redirects=True, timeout=60, headers={"User-Agent": C.USER_AGENT})
r.raise_for_status() r.raise_for_status()
lm = r.headers.get("last-modified") lm = r.headers.get("last-modified")
if not lm: if not lm:
raise RuntimeError(f"{url}: kein Last-Modified-Header") return None, dt.date.today().strftime("%Y%m%d")
date = dt.datetime.strptime(lm, "%a, %d %b %Y %H:%M:%S GMT").strftime("%Y%m%d") date = dt.datetime.strptime(lm, "%a, %d %b %Y %H:%M:%S GMT").strftime("%Y%m%d")
return f"{src}-{lm}", date return f"{src}-{lm}", date
@@ -347,12 +349,18 @@ def prepare(source: str, state: dict, zip_path: Path | None = None, force: bool
state[source + "@checked"] = time.time() state[source + "@checked"] = time.time()
url = gtfs_url(source) url = gtfs_url(source)
name, version = remote_id(source, url) name, version = remote_id(source, url)
if f"{name} #{FORMAT}" == state.get(source) and not force: if name and f"{name} #{FORMAT}" == state.get(source) and not force:
log.info("[%s] Kein neuer Fahrplan (%s)", source, name) log.info("[%s] Kein neuer Fahrplan (%s)", source, name)
return return
zip_path = work / "gtfs.zip" zip_path = work / "gtfs.zip"
log.info("[%s] Lade Fahrplan %s", source, name) log.info("[%s] Lade Fahrplan %s", source, name or "(ohne Datum vom Server)")
download(url, zip_path) download(url, zip_path)
if not name: # ohne Datum vom Server: am Inhalt erkennen, ob es Neues gibt
with open(zip_path, "rb") as f:
name = f"{source}-{hashlib.file_digest(f, 'sha256').hexdigest()[:16]}"
if f"{name} #{FORMAT}" == state.get(source) and not force:
log.info("[%s] Kein neuer Fahrplan (gleicher Inhalt)", source)
return
t = time.time() t = time.time()
version = version or zip_path.stem # (nach dem Glätten hiesse die Datei sonst "normalized") version = version or zip_path.stem # (nach dem Glätten hiesse die Datei sonst "normalized")