fix(scrapers/backend): socks5 health-probe + status Literal + #1820 ext_id=0 dedup #1825

Merged
lekss361 merged 1 commit from fix/scrapers-phase1-backend into main 2026-06-20 07:21:21 +00:00
Owner

Phase-1 polish backend для tradein scrapers (3 минорных фикса, непересекающиеся файлы).

Изменения

  1. socks5 IP-проба в /scraper/health_probe_current_ip использует httpx.AsyncClient(proxy=...); для cian/yandex прокси — схема socks5://, а httpx без extra socksio рейзит → current_ip=null на UI. Фикс: httpx>=0.27.0httpx[socks]>=0.27.0 (тянет socksio с socks5+auth). Кода в admin.py не требуется — extra делает socks5 прозрачным. socksio подтверждён в локальном uv.lock.
    ⚠️ Деплой: backend Python-dep change → CI пересобирает образ, нужен recreate tradein-backend (не только browser). uv.lock в tradein-mvp/.gitignore (backend/uv.lock) — не трекается; CI регенерит lock из pyproject при сборке.
  2. status query-param whitelistGET /scrape/runs параметр status принимал любую строку → ограничен Literal["done","running","banned","zombie","failed","cancelled"] | None. Невалидный status → 422.
  3. #1820 ext_id=0 dedup-гард — graceful-skip новостройки без parseable id давал HouseInfo(ext_id=0)match_or_create_house(ext_id="0") → Tier-1 source_exact склеивал ВСЕ безымянные новостройки в один bogus house avito:0 + мусорная house_sources-привязка. Фикс: гард в save_house_catalog_enrichment — skip персиста когда нет НИ ext_id, НИ адреса (id-less + characteristic-less). Если адрес есть (developmentPage без avitoId) — персист продолжается, падает на fingerprint/geo tier (корректно). Стратегия ext_id=None отвергнута: потребовала бы менять сигнатуру match_or_create_house(ext_id: str).

Файлы

  • tradein-mvp/backend/pyproject.toml
  • tradein-mvp/backend/app/api/v1/admin.py
  • tradein-mvp/backend/app/services/scrapers/avito_houses.py
  • tradein-mvp/backend/tests/test_scraper_admin_apis.py (+2 теста status 422/200)
  • tradein-mvp/backend/tests/test_avito_houses_dedup.py (+2 теста #1820)

Проверка

ruff — pass. pytest: test_scraper_admin_apis (12) + test_avito_houses_dedup (9) + parse (26) + newbuilding_sweep (9) + matching (47) — все зелёные.

Phase-1 polish backend для tradein scrapers (3 минорных фикса, непересекающиеся файлы). ## Изменения 1. **socks5 IP-проба в `/scraper/health`** — `_probe_current_ip` использует `httpx.AsyncClient(proxy=...)`; для cian/yandex прокси — схема `socks5://`, а httpx без extra `socksio` рейзит → `current_ip=null` на UI. Фикс: `httpx>=0.27.0` → `httpx[socks]>=0.27.0` (тянет socksio с socks5+auth). Кода в admin.py не требуется — extra делает socks5 прозрачным. socksio подтверждён в локальном uv.lock. ⚠️ **Деплой**: backend Python-dep change → CI пересобирает образ, нужен **recreate tradein-backend** (не только browser). `uv.lock` в `tradein-mvp/.gitignore` (`backend/uv.lock`) — не трекается; CI регенерит lock из pyproject при сборке. 2. **status query-param whitelist** — `GET /scrape/runs` параметр `status` принимал любую строку → ограничен `Literal["done","running","banned","zombie","failed","cancelled"] | None`. Невалидный status → 422. 3. **#1820 ext_id=0 dedup-гард** — graceful-skip новостройки без parseable id давал `HouseInfo(ext_id=0)` → `match_or_create_house(ext_id="0")` → Tier-1 source_exact склеивал ВСЕ безымянные новостройки в один bogus house `avito:0` + мусорная house_sources-привязка. Фикс: гард в `save_house_catalog_enrichment` — skip персиста когда нет НИ ext_id, НИ адреса (id-less + characteristic-less). Если адрес есть (developmentPage без avitoId) — персист продолжается, падает на fingerprint/geo tier (корректно). Стратегия `ext_id=None` отвергнута: потребовала бы менять сигнатуру `match_or_create_house(ext_id: str)`. ## Файлы - `tradein-mvp/backend/pyproject.toml` - `tradein-mvp/backend/app/api/v1/admin.py` - `tradein-mvp/backend/app/services/scrapers/avito_houses.py` - `tradein-mvp/backend/tests/test_scraper_admin_apis.py` (+2 теста status 422/200) - `tradein-mvp/backend/tests/test_avito_houses_dedup.py` (+2 теста #1820) ## Проверка ruff — pass. pytest: test_scraper_admin_apis (12) + test_avito_houses_dedup (9) + parse (26) + newbuilding_sweep (9) + matching (47) — все зелёные.
lekss361 added 1 commit 2026-06-20 07:18:52 +00:00
fix(scrapers/backend): socks5 health-probe (httpx[socks]) + status Literal whitelist + #1820 ext_id=0 dedup-гард
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
8361961a44
- pyproject.toml: httpx[socks]>=0.27.0 — тянет socksio, socks5:// прокси в _probe_current_ip работает прозрачно
- admin.py list_scrape_runs_unified: status Literal["done","running","banned","zombie","failed","cancelled"] вместо str|None — невалидные значения → 422
- avito_houses.py save_house_catalog_enrichment: гард ext_id=0 + нет адреса → skip without DB touch; два id-less novostroyka URL не схлопываются в bogus avito:0 в house_sources
- тесты: test_unified_runs_invalid_status_422 + test_unified_runs_valid_statuses_200; test_save_house_catalog_enrichment_skips_zero_ext_id_no_address + *_with_address_persists
lekss361 merged commit 298b43e399 into main 2026-06-20 07:21:21 +00:00
lekss361 deleted branch fix/scrapers-phase1-backend 2026-06-20 07:21:21 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#1825
No description provided.