Авито изредка держит соединение до упора, goto падает по 90-секундному
таймауту и прогон умирает целиком. В наблюдавшемся случае это был не отказ:
вкладка показывала нормальную выдачу, маркеров фаервола и PoW не было.
Но тихий отказ выглядит так же, поэтому ретрай не слепой: перед каждым
повтором читаем то, что есть в документе, и прогоняем через _guard — реальный
блок останавливает прогон со своей причиной. Исчерпали 3 попытки — жёсткий
стоп с причиной nav_timeout, а не бесконечный повтор.
Авито дорисовывает выдачу после domcontentloaded, и content() иногда попадает
ровно в смену документа — Playwright бросает "page is navigating and changing
the content". Это не отказ площадки, но прогон падал целиком: на 1110-й
карточке потеряно 100 несброшенных строк.
Ретрай узкий — только на этот текст ошибки и только 4 попытки; любая другая
ошибка поднимается как есть, гварды блокировки не ослаблены. runs/ (планы и
CSV прогонов) в .gitignore.
Коридоры считаются под конкретный URL выдачи. При --resume код брал свежий
args.base_url, поэтому запуск без повтора --base-url молча качал другую
выдачу под тем же batch_id. Теперь URL из плана, расхождение с аргументом —
явная ошибка вместо тихого выбора одного из двух.
Трек 1 эпика: нужен разовый корпус вторички Москвы+МО в msk_raw, а прод-скрейпер
для этого не подходит — его расписания, прокси-пул и сайдкар держат ЕКБ и трогать
их ради ручного замера нельзя.
Поэтому скрипт: браузер — уже открытый Chrome владельца с залогиненным техаккаунтом
(connect_over_cdp, своя вкладка, чужие вкладки/контекст/браузер не трогаем и не
закрываем; своего профиля не поднимаем); парсер — импорт _parse_html /
_extract_total_count / _is_firewall_page из scraper-kit, а не копия (копия разъедется
с прод-парсером на первом же DOM-drift); заливка — поток в psql через ssh, потому что
прямого доступа к прод-Postgres с локалки нет, а одиночный psql -c ломается на
квотинге.
avito_serp_ekb_only=False обязателен: с True парсер выбрасывает всё, где в URL нет
/ekaterinburg/ — из московской выдачи не осталось бы ни одной карточки.
Потолок Авито 30x60=1800 на запрос, поэтому план ценовых коридоров с бисекцией по
ГЕОМЕТРИЧЕСКОЙ середине: цены логнормальны, арифметическая середина 1млн..100млн
даёт вырожденно-пустую верхнюю половину. Коридор, который не влезает в 1800 даже
на минимальной ширине, помечается truncated и недобор пишется в batches.notes —
молчаливое усечение читалось бы как полный охват.
Стоп на первом признаке блока (403/439, 429, firewall, PoW, 0 карточек при ненулевом
счётчике) без ретраев: ретрай по забаненному техаккаунту только углубляет бан.
Дефолт — --measure 100, полный проход только по явному --full.