feat(scrapers): wire N1.ru city sweep — pipeline + scheduler + admin endpoint (#575) #745
No reviewers
Labels
No labels
admin
analytics
auth
automation
bug
business
chore
ci
compliance
data
data-moat
docs
duplicate
dx
enhancement
Fable 5 ревью
feedback/max
generative
GG-форсайт
needs-discussion
needs-human
observability
pause-bots
performance
priority/p0
priority/p1
priority/p2
priority/p3
scope/backend
scope/db
scope/devops
scope/frontend
scope/qa
scrapers
security
site-finder
stage/1
stage/2
status/blocked
status/done
status/needs-analysis
status/needs-fix
status/qa
status/ready
status/review
status/wip
tech-debt
tradein
ux
week ревью 1
wontfix
вторичка
ИРД
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: lekss361/gendesign#745
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "feat/575-n1-integration"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
n1.pyscraper existed (and was wired into the generic point-/scrapeendpoint) but had no city-sweep + schedule entry. Wire it up by mirroring the yandex sweep (N1 is a simple regional SERP — search → save, no houses/detail enrich):scrape_pipeline.run_n1_city_sweep+N1CitySweepCounters— anchors × pages →save_listings; cooperative cancel; abort afterN1_SWEEP_MAX_CONSECUTIVE_FAILURESconsecutive anchor failures (N1 has no block/rate exception classes).scheduler.trigger_n1_city_sweep_run+ dispatch branch (source='n1_city_sweep').data/sql/084—scrape_schedulesseed,enabled=true(vs dormant avito/yandex). #575's intent is to activate N1 as a source (acceptance = listings flowing); N1's anti-bot is milder than Avito/Yandex. One-lineUPDATE … SET enabled=falseto disable if it blocks.POST /api/v1/admin/scrape/n1(+GET /scrape/n1/runs) — on-demand city-sweep trigger with run tracking.estimator.sources_usedis derived from{lot.source for lot in listings}—n1flows in automatically once n1 listings exist, so no estimator change (item 4 auto-satisfied).Note on diff size
The pre-commit
ruff-formathook reflowed some pre-existing lines in the three touched files (e.g. collapsing a multi-linedatetime.combine(...)), so the diff is larger than the logical change. Those reflows are mechanical/whitespace-only (hook-enforced), not behavior.Test plan
tests/test_n1_city_sweep.py(5): aggregate counters,run_idthreading, empty-page short-circuit, mid-sweep cancel, consecutive-failure abort+ban. Mirrorstest_yandex_city_sweep(adapted for N1's 1-based pagination).ruffclean; imports OK.Acceptance (QA, post-deploy)
listings WHERE source='n1'≥ 100/day (scheduler runs nightly 02–05 UTC; or triggerPOST /admin/scrape/n1immediately). If N1 blocks the prod IP, the abort/ban kicks in andenabledcan be flipped off — no impact on other sources.n1inestimator.sources_usedfor EKB once n1 listings are present.Refs #575
✅ APPROVE
Wire N1.ru city sweep (#575). Большой дифф — в основном ruff-format reflow pre-existing строк (признано в PR); логическое изменение локализовано.
Correctness
run_n1_city_sweepточно зеркалит проверенныйrun_yandex_city_sweep: anchors×pages →save_listings(run_id=...), cooperativeis_cancelledперед каждым anchor, broad-Exception catch (у N1 нет block/rate exception-классов) +consecutive_failures≥3→mark_banned, пустая страница рвёт пагинацию.range(1, pages+1)) vs yandex 0-based — worker это отметил, тесты ассертят[1,2].trigger_n1_city_sweep_runзеркалит yandex-trigger (_claim_run, asyncio task, done-callback); dispatch-ветка добавлена.estimator.sources_usedавто-деривится из source листингов → изменение не нужно (item 4 issue авто-выполнен — верно).SQL 084 — idempotent (
ON CONFLICT DO NOTHING), BEGIN/COMMIT, зависит от 052, NN_ naming, нет коллизии с другими открытыми PR (sibling #746 — frontend).enabled=true— осознанная задокументированная активация по acceptance #575 (≥100 listings/день); avito/yandex были dormant из-за анти-бот риска, но N1 — мягче, с one-line kill-switch (UPDATE … enabled=false) и abort/ban-страховкой. В рамках intent issue, не data-loss/security риск.Tests — 5 offline orchestration-тестов (aggregate, run_id threading, empty-page, mid-sweep cancel, consecutive-failure abort), без сети/БД. 32 regression pass, ruff clean.
Scope/security — backend pipeline/scheduler/admin/sql + тест; нет secrets, нет self-extending триггера.
Advisory — дифф раздут ruff-format reflow'ом (шум); QA/ops следить за
enabled=trueактивацией post-deploy (abort/ban + kill-switch обрабатывают блок). Live behavior + ≥100/день → qa.