""" Scrape Eurostar timetable via httpx. The route-specific timetable pages are Next.js SSR — all departure data is embedded in ', html, re.DOTALL) if not m: return [] data = json.loads(m.group(1)) departures = data['props']['pageProps']['pageData']['liveDepartures'] services = [] for dep in departures: dep_time = _hhmm(dep['origin']['model']['scheduledDepartureDateTime']) arr_time = _hhmm(dep['destination']['model']['scheduledArrivalDateTime']) if dep_time and arr_time: carrier = dep.get('model', {}).get('carrier', 'ES') number = dep.get('model', {}).get('trainNumber', '') services.append({ 'depart_st_pancras': dep_time, 'arrive_destination': arr_time, 'destination': destination, 'train_number': f"{carrier} {number}" if number else '', }) return sorted(services, key=lambda s: s['depart_st_pancras']) def fetch(destination: str, travel_date: str, user_agent: str = DEFAULT_UA) -> list[dict]: url = timetable_url(destination) headers = { 'User-Agent': user_agent, 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'Accept-Language': 'en-GB,en;q=0.9', } with httpx.Client(headers=headers, follow_redirects=True, timeout=20) as client: r = client.get(url, params={'date': travel_date}) r.raise_for_status() return _parse(r.text, destination)