[tradein][scrapers] Avito: детект block/captcha-страниц (HTTP-200) → raise, не «0 lots» #823

Closed
opened 2026-05-30 19:40:15 +00:00 by lekss361 · 2 comments
Owner

Worker: auto-backend. Ветка от forgejo/main. СНАЧАЛА проверь дубль: если в avito.py уже есть content-block-detection (grep block/captcha/Доступ огранич) или это покрыто #769/#759 — закрой как done-in-другом-PR. НЕ запускай скрапер против живого Avito (IP забанен). Только unit-тест на фикстуре.

Задача

Avito может вернуть HTTP-200 с anti-bot/captcha-страницей → парсер находит 0 лотов → run «успешно» с 0 done, маскируя бан. Нужен детект block-page → raise (run=failed), + счётчик parse_failures для логов/Sentry.

Файлы (verify — могли дрейфнуть)

  • backend/app/services/scrapers/avito.py:217-231 — извлечение лотов
  • backend/app/services/scrapers/avito.py:371 — silent except: return None
  • backend/tests/ — существующий test_avito*

Definition of Done

  • Детектор block-page (маркеры: «Доступ ограничен»/captcha-форма/пустой state при 200) → raise доменного исключения (run failed, не 0-done).
  • ≥1 silent except: return None заменён на лог-warning + инкремент parse_failures.
  • Unit-тест на block-page фикстуре: ожидает raise/failed, не 0-lots-success.
  • pytest tests/ -k avito зелёный; ruff check чисто.

Не делать

  • Сетевых запросов к Avito нет. Cian/yandex не трогать. Дубль #769 → закрыть, не плодить.
> Worker: auto-backend. Ветка от forgejo/main. СНАЧАЛА проверь дубль: если в avito.py уже есть content-block-detection (grep `block`/`captcha`/`Доступ огранич`) или это покрыто #769/#759 — закрой как done-in-другом-PR. НЕ запускай скрапер против живого Avito (IP забанен). Только unit-тест на фикстуре. ## Задача Avito может вернуть HTTP-200 с anti-bot/captcha-страницей → парсер находит 0 лотов → run «успешно» с 0 done, маскируя бан. Нужен детект block-page → raise (run=failed), + счётчик parse_failures для логов/Sentry. ## Файлы (verify — могли дрейфнуть) - `backend/app/services/scrapers/avito.py:217-231` — извлечение лотов - `backend/app/services/scrapers/avito.py:371` — silent `except: return None` - `backend/tests/` — существующий test_avito* ## Definition of Done - [ ] Детектор block-page (маркеры: «Доступ ограничен»/captcha-форма/пустой state при 200) → raise доменного исключения (run failed, не 0-done). - [ ] ≥1 silent `except: return None` заменён на лог-warning + инкремент parse_failures. - [ ] Unit-тест на block-page фикстуре: ожидает raise/failed, не 0-lots-success. - [ ] `pytest tests/ -k avito` зелёный; `ruff check` чисто. ## Не делать - Сетевых запросов к Avito нет. Cian/yandex не трогать. Дубль #769 → закрыть, не плодить.
lekss361 added this to the Night batch — 2026-05-31 milestone 2026-05-30 19:40:15 +00:00
lekss361 added the
priority/p3
scope/backend
scrapers
tradein
status/ready
labels 2026-05-30 19:40:15 +00:00
bot-backend added
status/wip
and removed
status/ready
labels 2026-05-30 19:46:07 +00:00
bot-backend self-assigned this 2026-05-30 19:46:07 +00:00
bot-backend added
status/review
and removed
status/wip
labels 2026-05-30 19:53:26 +00:00
Collaborator

PR #830 (feat/823-avito-blockpage) → review. Дуп-чек: основная часть (HTTP-200 block/captcha → raise) УЖЕ реализована ранее — _is_firewall_page() (avito.py:188, маркеры «доступ ограничен»/«проблема с ip»/firewall-container) + AvitoContentBlockedError (avito.py:374-376, page==1/200/0-lots, наследует AvitoBlockedError). Реальный незакрытый gap — silent except: return None в _dom_card_to_lot:534 без observability: добавлен parse_failures счётчик + logger.warning. +фикстура block-page + 8 тестов, 122 passed, ruff clean. Block-detection логика не тронута.

PR #830 (feat/823-avito-blockpage) → review. **Дуп-чек:** основная часть (HTTP-200 block/captcha → raise) УЖЕ реализована ранее — `_is_firewall_page()` (avito.py:188, маркеры «доступ ограничен»/«проблема с ip»/firewall-container) + `AvitoContentBlockedError` (avito.py:374-376, page==1/200/0-lots, наследует AvitoBlockedError). Реальный незакрытый gap — silent `except: return None` в `_dom_card_to_lot:534` без observability: добавлен `parse_failures` счётчик + `logger.warning`. +фикстура block-page + 8 тестов, 122 passed, ruff clean. Block-detection логика не тронута.
bot-reviewer added
status/qa
and removed
status/review
labels 2026-05-30 20:01:55 +00:00
Collaborator

QA PASS — Avito block-page detect + parse_failures observability (PR #830, merged). Verified по merged diff. Unit-only (live Avito не дёргался — IP забанен, корректно).

Дуп-чек (воркер честно отработал): основной детектор HTTP-200 block/captcha → raise УЖЕ существовал (_is_firewall_page + AvitoContentBlockedError, из #754/#779/#788) — НЕ дублировался. Реальный незакрытый gap = observability на silent except: return None.

Code (avito.py):

  • self.parse_failures: int = 0 в __init__.
  • silent except в _dom_card_to_lot теперь: parse_failures += 1 + logger.warning(item_id, parse_failures, exc_info=True) перед return None (DoD #2).
  • Block-detection логика НЕ тронута (правильно — pre-existing).

Тесты (8, test_avito_blockpage.py) + фикстура avito_blockpage_sample.html:

  • _is_firewall_page → True на блок-фикстуре / False на SERP+empty.
  • _parse_html на блок-странице → [].
  • Тест 3 — fetch_around бросает AvitoContentBlockedError при 0-lots page=1 → гарантия что silent «0 lots success» НЕ происходит (основной DoD #1, теперь regression-covered).
  • parse_failures: старт 0 / early-return-не-инкрементит / exception-инкрементит / аккумулируется across cards.
  • 122 passed, ruff clean.

DoD: #1 (block→raise) pre-existing+now-tested, #2 (observability) new, #3 (fixture-raise test), #4 (pytest+ruff) — все .

status/done, closing.

✅ **QA PASS** — Avito block-page detect + parse_failures observability (PR #830, merged). Verified по merged diff. Unit-only (live Avito не дёргался — IP забанен, корректно). **Дуп-чек (воркер честно отработал):** основной детектор HTTP-200 block/captcha → raise УЖЕ существовал (`_is_firewall_page` + `AvitoContentBlockedError`, из #754/#779/#788) — НЕ дублировался. Реальный незакрытый gap = observability на silent `except: return None`. **Code (`avito.py`):** - `self.parse_failures: int = 0` в `__init__`. - silent `except` в `_dom_card_to_lot` теперь: `parse_failures += 1` + `logger.warning(item_id, parse_failures, exc_info=True)` перед `return None` (DoD #2). ✅ - Block-detection логика НЕ тронута (правильно — pre-existing). ✅ **Тесты (8, `test_avito_blockpage.py`) + фикстура `avito_blockpage_sample.html`:** - `_is_firewall_page` → True на блок-фикстуре / False на SERP+empty. ✅ - `_parse_html` на блок-странице → `[]`. ✅ - **Тест 3 — `fetch_around` бросает `AvitoContentBlockedError` при 0-lots page=1** → гарантия что silent «0 lots success» НЕ происходит (основной DoD #1, теперь regression-covered). ✅ - `parse_failures`: старт 0 / early-return-не-инкрементит / exception-инкрементит / аккумулируется across cards. ✅ - 122 passed, ruff clean. ✅ DoD: #1 (block→raise) pre-existing+now-tested, #2 (observability) new, #3 (fixture-raise test), #4 (pytest+ruff) — все ✅. → `status/done`, closing.
bot-qa added
status/done
and removed
status/qa
labels 2026-05-30 20:04:43 +00:00
Sign in to join this conversation.
No project
No assignees
3 participants
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#823
No description provided.