- avito.py: AVITO_PROXY_URL → proxies в curl_cffi AsyncSession; firewall-детект
«Доступ ограничен: проблема с IP» на HTTP 200 → AvitoBlockedError (раньше бан
проходил молча как 0-cards); ротация мобильного IP через changeip-ссылку
(_rotate_ip) с retry до avito_proxy_max_rotations; transient-retry на сетевых
обрывах мобильного канала.
- config.py: avito_proxy_url / avito_proxy_rotate_url / avito_proxy_max_rotations.
- #726: sortTimeStamp → дата в MSK (UTC+3 fixed offset), а не UTC — совпадает с
датой на сайте; off-by-one для постов 00:00–03:00 MSK устранён.
- tests: firewall-детект (HTTP 200), ротация+повтор, exhausted-rotation; serp_date
переведён на MSK.
Live-verified с прод-сервера: mobile proxy снимает firewall (0→48 карточек),
ротация IP 188.162.65.168→94.25.229.234. Без env AVITO_PROXY_URL поведение не
меняется (dev). Требует deploy (#659) + env AVITO_PROXY_URL/ROTATE_URL на VPS.
Add global request delay floor + per-source delay management.
- 054: seed 'global'=0 + per-source rows (avito=7, cian=5, n1=5, domrf=5, rosreestr=5)
using ON CONFLICT DO NOTHING; reuses existing 053 table from #484
- scraper_settings.py: get_scraper_delay() = max(per_source, global); _GLOBAL_KEY,
refactored _get_setting_cached(); preserved yandex umbrella alias logic
- admin.py: GET /scraper-settings + PUT /scraper-settings/{source} (ge=0.0, le=60.0);
cache invalidation on update; CAST(:d AS numeric) per psycopg v3
- avito/cian/n1 scrapers wired (yandex was wired by #484)
- 18 unit tests pass (10 original updated for max() + 8 new global delay tests)
Closes follow-up gap from #486 (Cian admin slider min=0 now accepted by API).
DOM-путь (_dom_card_to_lot) — основной для Avito: mobile API отдаёт
бан, формат __initialState__ устарел, так что почти все объявления
идут через него. Но он не извлекал фото вообще, а адрес брал мёртвым
селектором [class*="geo-address"] — поэтому объявления Avito оставались
без фото (серый блок в Сводке) и с заглушкой «Екатеринбург (Avito)».
Теперь:
- фото — из <img itemprop="image"> карточки-слайдера (до 5 шт);
- адрес — первый <p> внутри data-marker="item-location" (улица + дом).
Селекторы проверены на живой выдаче Avito.