"""Auto Credit alternative factor — scrape real Thai vehicle sales from Trading Economics. Source: https://tradingeconomics.com/thailand/total-vehicle-sales Server-rendered HTML (per `har-derived-api-client` guidance, no JSON API — the HAR capture shows only ads/analytics). Three tables carry the data: Table 1 (announcements): "New Car Sales YoY" rows — latest YoY% per month. Table 2 (related indicators): Auto Exports, Vehicle Production, Passenger Car Sales current values. Table 3 (main series): Total Vehicle Sales `[latest, prev, high, low, range, units, freq, seasonality]`. We parse these so the Auto Credit factor can use vehicle-sales momentum (YoY%) and the current total, which is the real, non-mock input the user asked for. """ from __future__ import annotations import html import re from dataclasses import dataclass from typing import Optional from urllib.request import Request, urlopen _USER_AGENT = ( "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 " "(KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36" ) _URL = "https://tradingeconomics.com/thailand/total-vehicle-sales" class AutoCreditError(Exception): """Raised when the Trading Economics page cannot be fetched or parsed.""" @dataclass(frozen=True) class AutoCreditSnapshot: total_vehicle_sales: Optional[float] = None # latest units prev_vehicle_sales: Optional[float] = None # prior period units new_car_sales_yoy: Optional[float] = None # latest % YoY prev_new_car_sales_yoy: Optional[float] = None vehicle_production: Optional[float] = None passenger_car_sales: Optional[float] = None auto_exports: Optional[float] = None as_of: str = "" source: str = "tradingeconomics" def to_dict(self) -> dict: return { "source": self.source, "as_of": self.as_of, "total_vehicle_sales": self.total_vehicle_sales, "prev_vehicle_sales": self.prev_vehicle_sales, "new_car_sales_yoy": self.new_car_sales_yoy, "prev_new_car_sales_yoy": self.prev_new_car_sales_yoy, "vehicle_production": self.vehicle_production, "passenger_car_sales": self.passenger_car_sales, "auto_exports": self.auto_exports, } def _fetch(url: str = _URL, timeout: float = 30.0) -> str: req = Request(url, headers={"User-Agent": _USER_AGENT, "Accept": "text/html"}) try: with urlopen(req, timeout=timeout) as resp: raw = resp.read() except Exception as exc: raise AutoCreditError(f"failed to fetch {url}: {exc}") from exc try: return raw.decode("utf-8") except UnicodeDecodeError: return raw.decode("latin-1", "ignore") def _tables(html_text: str) -> list[str]: return re.findall(r"