Add vehicle color parsing

This commit is contained in:
qananasikq
2026-08-03 21:05:45 +03:00
parent 72e78de1d7
commit 9c1756a959
3 changed files with 85 additions and 19 deletions

View File

@@ -420,11 +420,20 @@ class EncarMapper:
return self._clean_base_model_name(translated)
def _translate_color(self, color_raw: str) -> str:
value = self._as_str(color_raw)
value = re.sub(r"\s+", "", self._as_str(color_raw))
if not value:
return "other"
return COLOR_TRANSLATIONS.get(value, self._translate_text(value).lower() or "other")
def apply_batch_color(self, record: CarRecord, vehicle_data: dict[str, Any]) -> None:
spec = vehicle_data.get("spec")
if not isinstance(spec, dict):
return
color_raw = self._as_str(spec.get("colorName") or spec.get("customColor") or "")
if color_raw:
record.color = self._translate_color(color_raw)
def _to_float(self, value: Any) -> float | None:
if value is None:
return None
@@ -1500,24 +1509,33 @@ class EncarScraper:
for i in range(0, len(tasks), BATCH_VEHICLES_CHUNK_SIZE):
chunks.append(tasks[i:i + BATCH_VEHICLES_CHUNK_SIZE])
def _fetch_chunk(chunk: list[tuple[int, str]]) -> list[tuple[int, list[ImageRecord]]]:
def _fetch_chunk(chunk: list[tuple[int, str]]) -> list[tuple[int, list[ImageRecord], dict[str, Any]]]:
ids_str = ",".join(vid for _, vid in chunk)
path = f"/v1/readside/vehicles?vehicleIds={ids_str}&include=PHOTOS"
for attempt in range(2):
path = f"/v1/readside/vehicles?vehicleIds={ids_str}&include=SPEC,PHOTOS"
for attempt in range(3):
try:
resp = pool.request("GET", path, timeout=15, retries=False)
if resp.status == 200:
if not resp.data:
return [(ri, []) for ri, _ in chunk]
return [(ri, [], {}) for ri, _ in chunk]
vehicles = json.loads(resp.data.decode("utf-8", errors="ignore"))
# Маппим по vehicleId, а не по индексу — API может пропускать удалённые ID
id_to_rec: dict[str, int] = {vid: ri for ri, vid in chunk}
result: list[tuple[int, list[ImageRecord]]] = []
for vehicle_data in vehicles:
result: list[tuple[int, list[ImageRecord], dict[str, Any]]] = []
matched_record_indexes: set[int] = set()
for vehicle_position, vehicle_data in enumerate(vehicles):
vid = str(vehicle_data.get("vehicleId") or vehicle_data.get("id") or "")
rec_idx = id_to_rec.get(vid)
rec_idx = None
if vehicle_position < len(chunk):
positional_rec_idx = chunk[vehicle_position][0]
if positional_rec_idx not in matched_record_indexes:
rec_idx = positional_rec_idx
if rec_idx is None:
rec_idx = id_to_rec.get(vid)
if rec_idx is None:
continue
if rec_idx in matched_record_indexes:
continue
matched_record_indexes.add(rec_idx)
photos_raw = vehicle_data.get("photos") or []
images: list[ImageRecord] = []
seen_paths: set[str] = set()
@@ -1535,28 +1553,28 @@ class EncarScraper:
order_index=order,
))
images.sort(key=lambda x: x.order_index)
result.append((rec_idx, images))
result.append((rec_idx, images, vehicle_data))
return result
if resp.status in (429, 503):
time.sleep(1 + attempt * 2)
continue
return [(ri, []) for ri, _ in chunk]
return [(ri, [], {}) for ri, _ in chunk]
except json.JSONDecodeError:
return [(ri, []) for ri, _ in chunk]
return [(ri, [], {}) for ri, _ in chunk]
except Exception as exc:
logger.debug("Batch photo chunk error (attempt %d): %s", attempt + 1, exc)
if attempt < 1:
if attempt < 2:
time.sleep(1)
return [(ri, []) for ri, _ in chunk]
return [(ri, [], {}) for ri, _ in chunk]
results: dict[int, list[ImageRecord]] = {}
results: dict[int, tuple[list[ImageRecord], dict[str, Any]]] = {}
with ThreadPoolExecutor(max_workers=30) as executor:
futures = {executor.submit(_fetch_chunk, ch): ch for ch in chunks}
for future in as_completed(futures):
try:
for rec_idx, images in future.result():
if images:
results[rec_idx] = images
for rec_idx, images, vehicle_data in future.result():
if vehicle_data:
results[rec_idx] = (images, vehicle_data)
except Exception as exc:
logger.warning("Batch photo future failed: %s", exc)
@@ -1565,7 +1583,10 @@ class EncarScraper:
fallback_count = 0
for rec_idx, item in probe_tasks:
if rec_idx in results:
records[rec_idx].images = results[rec_idx]
images, vehicle_data = results[rec_idx]
if images:
records[rec_idx].images = images
self.car_mapper.apply_batch_color(records[rec_idx], vehicle_data)
api_ok += 1
else:
fallback_count += 1