fix encar id mapping and docker build stability

This commit is contained in:
qananasikq
2026-04-21 19:35:12 +03:00
parent eba3750f15
commit 1c5c30e31e
4 changed files with 120 additions and 19 deletions

View File

@@ -42,6 +42,7 @@ BATCH_VEHICLES_CHUNK_SIZE = 20
ENCAR_DETAIL_URL_TEMPLATE = "https://www.encar.com/dc/dc_cardetailview.do?carid={vehicle_id}"
ENCAR_IMAGE_BASE = "https://ci.encar.com"
VEHICLE_ID_RE = re.compile(r"(?:carid|vehicleId)=?(\d+)")
NUMERIC_ID_RE = re.compile(r"(\d{6,})")
PHOTO_VEHICLE_ID_RE = re.compile(r"/(\d+)_\d+\.(?:jpg|jpeg|png|webp)$", re.IGNORECASE)
# Максимальный номер фото для пробинга и допустимые промахи подряд
@@ -155,30 +156,24 @@ class RuntimeFilterSpec:
@dataclass(slots=True)
class EncarMapper:
def map_to_car_record(self, vehicle_url: str, payload: dict[str, Any], probe_all_photos: bool = False) -> CarRecord:
vehicle_id = self._extract_vehicle_id(vehicle_url) or str(
payload.get("Id") or payload.get("vehicleId") or ""
)
vehicle_id = self._resolve_vehicle_id(vehicle_url, payload)
origin_id = f"encar:{vehicle_id}"
parser_id = f"encar:{vehicle_id}"
origin_url = vehicle_url or ENCAR_DETAIL_URL_TEMPLATE.format(vehicle_id=vehicle_id)
url_vehicle_id = self._extract_vehicle_id(vehicle_url)
if vehicle_url and url_vehicle_id == vehicle_id:
origin_url = vehicle_url
else:
origin_url = ENCAR_DETAIL_URL_TEMPLATE.format(vehicle_id=vehicle_id)
brand = self._as_str(payload.get("Manufacturer") or payload.get("Brand") or "UNKNOWN")
# Перевод бренда на русский
brand = BRAND_TRANSLATIONS.get(brand, brand)
# Model + Badge + BadgeDetail = полное название
# Нужна только базовая модель (без trim/sub-trim)
model_raw = self._as_str(payload.get("Model") or "UNKNOWN")
badge = self._as_str(payload.get("Badge") or "")
badge_detail = self._as_str(payload.get("BadgeDetail") or "")
# Полное описание модели: "Model / Badge BadgeDetail"
model_parts = [model_raw]
if badge:
model_parts.append(badge)
if badge_detail and badge_detail not in badge:
model_parts.append(badge_detail)
model = " / ".join(model_parts) if len(model_parts) > 1 else model_parts[0]
model = self._translate_text(model)
model = self._translate_text(model_raw)
year = self._to_year(payload.get("FormYear") or payload.get("Year"))
# Price в 만원 (10 000 KRW) → переводим в KRW
@@ -283,6 +278,66 @@ class EncarMapper:
match = VEHICLE_ID_RE.search(vehicle_url)
return match.group(1) if match else None
def _resolve_vehicle_id(self, vehicle_url: str | None, payload: dict[str, Any]) -> str:
# 1) Из URL (carid=123...)
from_url = self._extract_vehicle_id(vehicle_url)
if from_url:
return from_url
# 2) Из явных полей payload
for key in ("Id", "id", "vehicleId", "VehicleId", "carId", "carid"):
value = payload.get(key)
extracted = self._extract_numeric_id(value)
if extracted:
return extracted
# 3) Из фото-пути (например /.../41854374_001.jpg)
photos = payload.get("Photos") or []
if isinstance(photos, list):
for raw in photos:
if not isinstance(raw, dict):
continue
location = raw.get("location") or raw.get("Location") or ""
extracted = self._extract_numeric_id(location)
if extracted:
return extracted
# 4) Фолбэк: любой id-like ключ в payload
fallback = self._find_any_numeric_id(payload)
if fallback:
return fallback
raise ValueError("Cannot resolve numeric Encar vehicle id")
def _extract_numeric_id(self, value: Any) -> str | None:
if value is None:
return None
if isinstance(value, int):
return str(value)
text = self._as_str(value)
if not text:
return None
match = NUMERIC_ID_RE.search(text)
return match.group(1) if match else None
def _find_any_numeric_id(self, payload: dict[str, Any]) -> str | None:
stack: list[Any] = [payload]
while stack:
current = stack.pop()
if isinstance(current, dict):
for key, value in current.items():
if isinstance(key, str) and "id" in key.lower():
extracted = self._extract_numeric_id(value)
if extracted:
return extracted
if isinstance(value, (dict, list)):
stack.append(value)
elif isinstance(current, list):
for item in current:
if isinstance(item, (dict, list)):
stack.append(item)
return None
def _build_slug(self, brand: str, model: str, vehicle_id: str) -> str:
raw = re.sub(r"[^a-z0-9]+", "-", f"{brand}-{model}-{vehicle_id}".lower()).strip("-")
return raw or f"encar-{vehicle_id}"