gendesign/tradein-mvp/backend/app/services/scrapers/domclick_exceptions.py
bot-backend 43b392b809
All checks were successful
CI / changes (pull_request) Successful in 7s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
feat(tradein/domclick): local-runner + ingest tooling → main (split from parked Layer-B)
Выделяет МЕРДЖАБЕЛЬНУЮ часть DomClick-тулинга из запаркованного PR #2005
(BLOCKED #2000 — прод Layer-B скрейпер через прокси режет QRATOR-403):

- scripts/domclick_local_runner.py — ручной offline-сборщик с домашнего IP:
  SERP-enumerate (фронт, BFF-JSON режет QRATOR) + card __SSR_STATE__ +
  offer-card v3 (AVM price_prediction + sold_similar). --enum-cache (enumerate
  1 раз → файл с sentinel → следующий запуск грузит кэш и пропускает enumerate),
  wait_for_selector (SERP-карточки догидрируются), resume по id. Self-contained.
- scripts/ingest_domclick_jsonl.py — JSONL → trade-in БД (save_listings +
  house-match в SAVEPOINT + save_detail_enrichment, идемпотентно, --limit/--dry-run).
- app/services/scrapers/domclick_detail.py + domclick_exceptions.py — card-SSR
  parse + save_detail_enrichment (нужны ингесту). Импортятся ТОЛЬКО ингестом
  (operator-run); прод-runtime их не дёргает (dormant в образе).
- tests/scrapers/test_domclick_detail.py + обновлённый scripts/README.md.

НЕ включает прод Layer-B (tasks/domclick_detail_backfill.py, scheduler-расписание,
data/sql/139_*) — остаётся запаркован на PR #2005 до чистого прокси (#2000).
БД-схема не меняется (detail-колонки уже в проде, миграции нет).

Live-validated: раннер качает ЕКБ-вторичку прямо сейчас (600+ карт, 0 блоков),
ингест залил их в прод-БД (house_matched, идемпотентно).
2026-06-28 10:26:52 +03:00

27 lines
1.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""DomClick-specific exceptions для anti-bot detection."""
class DomClickBlockedError(Exception):
"""DomClick BFF вернул QRATOR block-страницу (HTTP 200 + block HTML).
QRATOR (qrator.net) — WAF/DDoS-защита domclick.ru. Блокирует datacenter-IP
и возвращает HTML с маркерами: "qrator", "bot_mitigation", "система защиты",
"403 | домклик", "captcha", "access denied".
Обходится через shared mobile proxy (BrowserFetcher(source="domclick") →
generic provider → мобильный egress).
"""
class DomClickParseError(Exception):
"""DomClick detail-карточка получена (HTTP 200, не block), но SSR-стейт
не извлекается / не парсится.
Возникает в Layer B (domclick_detail.py) когда:
- `window.__SSR_STATE__` не найден в HTML (но это и не challenge-страница);
- object-литерал не сбалансирован по скобкам;
- json.loads падает после санитайза bare `undefined` → `null`.
В отличие от DomClickBlockedError (anti-bot), это сигнал дрейфа схемы карточки
или повреждённого ответа — оркестратор считает его parse-failure, а не блоком.
"""