[tradein][scrapers] Avito ЖК-enrichment не долетает в БД — отзывы/тип/история по дому пусты (house_reviews=0, avito_validated_at=0) #1789

Closed
opened 2026-06-19 15:36:10 +00:00 by lekss361 · 1 comment
Owner

Проблема

Данные Avito ЖК-страницы (/catalog/houses/<slug>/<id>) — отзывы о доме, тип дома, история объявлений по дому — почти не попадают в БД, хотя avito_houses.py их парсит, а на живой странице они присутствуют. Это ключевые для продукта поля.

Доказательства (live probe 2026-06-19)

  • Живой дом ул. Сони Морозовой 190 (Avito id 572538): страница показывает рейтинг 4.7, 3 отзыва, тип, год, историю. В нашей БД этот дом — только source='derived' заглушки с NULL (ext_house_id 572538 не привязан).
  • house_reviews = 0 строк по всем источникам (таблица 014_house_reviews.sql; парсеры _parse_reviews/_parse_single_review существуют, оркестратор вызывает save_reviews).
  • houses (13117 строк): rating_score у 13, reviews_count>0 у 32, house_type 15% (2030), year_built 25% (3297), avito_validated_at IS NOT NULL = 0 у ВСЕХ домов.
  • house_placement_history: 90340 строк, но source = avito_imv (35653) + yandex_valuation (54707); из ЖК-виджета housePlacementHistory (source='avito_widget') = 0 строк.
  • houses по source: derived 7124 (rating 4), avito 4083 (rating 7, type 18), cian 776, yandex_valuation 481 — таблица в основном тонкие derived-заглушки из адресов листингов.

Корневая причина (гипотеза)

Дрейф структуры window.__preloadedState__ Avito. avito_houses.py парсит сводку частично, но виджеты reviews.props.entries[type=rating] (avito_houses.py:430) и housePlacementHistory (:501) отдают пусто → UPSERT кладёт NULL. Прогоны рапортуют houses_enriched: 17-37, но счётчик считает попытки парса, не реальные записи. __preloadedState__ как JS-global уже съеден SPA — скрейпер берёт его regex'ом из сырого HTML; для housePage частично работает, для reviews.entries + placement — нет (вероятно переименованы / вынесены в lazy XHR).

Что сделать

  1. Снять сырой fetched-HTML дома через tradein-browser (/catalog/houses/ekaterinburg/ul_soni_morozovoy_190/572538) → сверить фактическую структуру __preloadedState__ с ожидаемой в _get_widget/_parse_reviews/_parse_placement_history.
  2. Починить пути виджетов reviews.entries + housePlacementHistory; для отзывов, если entries вынесены в пагинацию — пройти по nextPageUrl.
  3. Убедиться, что rating_score/reviews_count/house_type/year_built/avito_validated_at реально попадают в UPSERT houses (:790-880; сейчас COALESCE может молча сохранять NULL).
  4. Добавить guard: виджет вернул 0 entries → WARNING (сейчас тихо проходит).

Усилие

M (dev-заход с живым fetched-HTML + правки парсера/UPSERT + тест на реальном доме).

Файлы: tradein-mvp/backend/app/services/scrapers/avito_houses.py; таблицы houses / house_reviews / house_placement_history.
Cross-ref: #883/#885 (camoufox migration). Анализ: vault research/Avito_Scraper_Endpoint_Map_0619.md.

## Проблема Данные Avito ЖК-страницы (`/catalog/houses/<slug>/<id>`) — **отзывы о доме, тип дома, история объявлений по дому** — почти не попадают в БД, хотя `avito_houses.py` их парсит, а на живой странице они присутствуют. Это ключевые для продукта поля. ## Доказательства (live probe 2026-06-19) - Живой дом ул. Сони Морозовой 190 (Avito id `572538`): страница показывает **рейтинг 4.7, 3 отзыва**, тип, год, историю. В нашей БД этот дом — только `source='derived'` заглушки с NULL (ext_house_id 572538 не привязан). - `house_reviews` = **0 строк** по всем источникам (таблица `014_house_reviews.sql`; парсеры `_parse_reviews`/`_parse_single_review` существуют, оркестратор вызывает save_reviews). - `houses` (13117 строк): `rating_score` у **13**, `reviews_count>0` у **32**, `house_type` 15% (2030), `year_built` 25% (3297), **`avito_validated_at IS NOT NULL = 0` у ВСЕХ домов**. - `house_placement_history`: 90340 строк, но `source` = `avito_imv` (35653) + `yandex_valuation` (54707); из ЖК-виджета `housePlacementHistory` (`source='avito_widget'`) = **0 строк**. - `houses` по source: derived 7124 (rating 4), avito 4083 (rating 7, type 18), cian 776, yandex_valuation 481 — таблица в основном тонкие derived-заглушки из адресов листингов. ## Корневая причина (гипотеза) Дрейф структуры `window.__preloadedState__` Avito. `avito_houses.py` парсит сводку частично, но виджеты `reviews.props.entries[type=rating]` (`avito_houses.py:430`) и `housePlacementHistory` (`:501`) отдают пусто → UPSERT кладёт NULL. Прогоны рапортуют `houses_enriched: 17-37`, но счётчик считает попытки парса, не реальные записи. `__preloadedState__` как JS-global уже съеден SPA — скрейпер берёт его regex'ом из сырого HTML; для `housePage` частично работает, для reviews.entries + placement — нет (вероятно переименованы / вынесены в lazy XHR). ## Что сделать 1. Снять **сырой fetched-HTML** дома через `tradein-browser` (`/catalog/houses/ekaterinburg/ul_soni_morozovoy_190/572538`) → сверить фактическую структуру `__preloadedState__` с ожидаемой в `_get_widget`/`_parse_reviews`/`_parse_placement_history`. 2. Починить пути виджетов `reviews.entries` + `housePlacementHistory`; для отзывов, если entries вынесены в пагинацию — пройти по `nextPageUrl`. 3. Убедиться, что `rating_score/reviews_count/house_type/year_built/avito_validated_at` реально попадают в UPSERT `houses` (`:790-880`; сейчас COALESCE может молча сохранять NULL). 4. Добавить guard: виджет вернул 0 entries → WARNING (сейчас тихо проходит). ## Усилие M (dev-заход с живым fetched-HTML + правки парсера/UPSERT + тест на реальном доме). **Файлы:** `tradein-mvp/backend/app/services/scrapers/avito_houses.py`; таблицы `houses` / `house_reviews` / `house_placement_history`. **Cross-ref:** #883/#885 (camoufox migration). Анализ: vault `research/Avito_Scraper_Endpoint_Map_0619.md`.
lekss361 added the
bug
priority/p1
scope/backend
scrapers
status/ready
tradein
labels 2026-06-19 15:36:46 +00:00
Author
Owner

⚠️ Уточнение корня по живой фикстуре (PR #спавнится): данные НЕ переехали в отдельный __mfe__ payload (моя первоначальная гипотеза). __preloadedState__ на месте (percent-encoded, декодится), но Avito вложил payload каждого виджета на уровень глубже под ключ с именем виджета: props.entriesprops.reviews.entries, props.itemsprops.housePlacementHistory.items и т.д. housePage не съехал (поэтому type/year парсились, а reviews/placement/miniSerp — 0). Фикс: хелпер _widget_payload(widget,type) + avito_validated_at=NOW() в UPSERT. На фикстуре: отзывы 3, история 8.

⚠️ Уточнение корня по живой фикстуре (PR #спавнится): данные НЕ переехали в отдельный `__mfe__` payload (моя первоначальная гипотеза). `__preloadedState__` на месте (percent-encoded, декодится), но Avito вложил payload каждого виджета на уровень глубже под ключ с именем виджета: `props.entries`→`props.reviews.entries`, `props.items`→`props.housePlacementHistory.items` и т.д. `housePage` не съехал (поэтому type/year парсились, а reviews/placement/miniSerp — 0). Фикс: хелпер `_widget_payload(widget,type)` + `avito_validated_at=NOW()` в UPSERT. На фикстуре: отзывы 3, история 8.
lekss361 added
status/review
and removed
status/ready
labels 2026-06-19 16:26:23 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
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#1789
No description provided.