ДомКлик — четвёртая площадка ручного сбора Москвы #3496
Merged
lekss361
merged 1 commit from 2026-09-12 12:05:19 +00:00
feat/msk-domclick-collector into main
1 commit
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
b4ca450f18 |
feat(msk-collector): адаптер DomClick — четвёртая площадка ручного сбора Москвы
All checks were successful
CI Trade-In / changes (pull_request) Successful in 16s
CI / changes (pull_request) Successful in 16s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI Trade-In / browser-tests (pull_request) Has been skipped
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
Авито, Циан и Яндекс по Москве уже залиты этим скриптом; ДомКлик был единственным непокрытым поставщиком, а таблица msk_raw.domclick_cards стояла пустой. Адаптер закрывает пробел. ## Почему локальный сборщик, а не параметризация боевого скрейпера Разведка настаивала на прод-пути, ссылаясь на замер «навигацией на BFF приходит только ChallengeTimeout, 9/9 и 6/6». Замер снят через пул мобильных прокси и к браузеру владельца не относится: оттуда повторная навигация на ту же ручку отдаёт 200 и валидный JSON — кука QRATOR в контексте уже решена, а сессия Сбер ID жива (auth/me → 200). Проверено 12.09.2026. Параметризация боевого скрейпера по городу остаётся отдельной задачей под РЕГУЛЯРНЫЙ сбор. Здесь нужна разовая заливка тем же инструментом, которым сделаны три предыдущие площадки. ## Устройство Регион задаётся GUID-ом Москвы в параметре address; aids, захардкоженный для ЕКБ, Москве не нужен — без него счётчик сходится с числом в заголовке выдачи. Бисекция — по цене, без комнатных корзин. Потолок пагинации замерен: offset 1980 отдаёт 20 карточек, 2000 даёт HTTP 400. Отсюда page_size 20, max_pages 100, hard_cap 2000. Полная вторичка Москвы — 23 690 по pagination.total, и план из 24 коридоров укладывается в потолок с запасом (максимум 1425). Счётчик берётся из pagination.total самой выдачи, а НЕ из отдельной count-ручки: та считает офферы вместе с дублями (25 898 против 7 651 на двушках) и для бисекции непригодна — разница пагинацией недостижима. Маппинг переиспользует DomClickScraper._map_item из кита. Гео-гард — собственный, по bbox Москвы с ТиНАО: _is_geo_ok кита сверяет offerRegionName с «Екатеринбургом», а в московской выдаче встречаются «x. Говорово», «пос. Птичное», «x. Ильичевка» — гард по названию региона молча резал бы легитимные лоты Новой Москвы. ## Экранирование в <pre> page.content() отдаёт сериализованный документ, а не тело ответа, и Chrome экранирует в текстовом узле амперсанд, угловые скобки и неразрывный пробел. Синтаксис JSON от этого не страдает, поэтому дефект тихий: разбор проходит, а в адресе и описании оседают & и — 29 штук на одной странице из двадцати карточек. Добавлен _unescape_pre_entities. Кавычки в список замен не входят намеренно: сериализатор экранирует их только в значениях атрибутов, а в текстовом узле кавычка остаётся собой. Разворот " превратил бы экранированную кавычку внутри строки JSON в невалидную последовательность и уронил бы разбор страницы целиком. ## Проверки Живой запрос через Loader: 20 карточек, geo_filtered 0, parse_failures 0. Первая тысяча строк на проде — 0 без цены, 0 без координат, 0 без площади, 0 с остатками экранирования, координаты внутри bbox. Нечисловая координата отбрасывает одну карточку, а не роняет прогон: сбор идёт часами без присмотра, и падение на середине коридора стоило бы дороже потерянного лота. Claude-Session: https://claude.ai/code/session_01NQb6WeJtagZwZnUsSjDizs |