fix(tradein): маркер полноты — encryptedPhones ИЛИ redirectPhones (#3191)
All checks were successful
CI Trade-In / changes (pull_request) Successful in 10s
CI / changes (pull_request) Successful in 13s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (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
CI Trade-In / backend-tests (pull_request) Successful in 5m21s
All checks were successful
CI Trade-In / changes (pull_request) Successful in 10s
CI / changes (pull_request) Successful in 13s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (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
CI Trade-In / backend-tests (pull_request) Successful in 5m21s
Ревью #3364. Требуя именно encryptedPhones, отбраковывали бы вечно необмеренный класс карточек «без телефона / только чат»: в очередь они возвращаются, а ключ не появится. redirectPhones измерен тем же замером #3192 и присутствует в обеих ветках (с куками и без). Текст ABORT: consecutive_none смешанный (фетч-ошибка + parse-None + недогруз) — «N подряд без обогащения», а не «недогруженных».
This commit is contained in:
parent
4b5f8fb54c
commit
78e3da6bc3
4 changed files with 31 additions and 9 deletions
|
|
@ -1010,7 +1010,7 @@ class Settings(BaseSettings):
|
||||||
# ── Порог полноты detail-страницы Яндекса (#3191) ────────────────────────
|
# ── Порог полноты detail-страницы Яндекса (#3191) ────────────────────────
|
||||||
# Полная карточка оффера — 3-5 МБ; недорендеренная приходит с HTTP 200, валидным
|
# Полная карточка оффера — 3-5 МБ; недорендеренная приходит с HTTP 200, валидным
|
||||||
# HTML и БЕЗ блока контактов (наблюдалось 1,8 МБ). Размер — второй признак к
|
# HTML и БЕЗ блока контактов (наблюдалось 1,8 МБ). Размер — второй признак к
|
||||||
# структурному (scraper_kit...yandex.detail.DETAIL_CONTACTS_MARKER); любой из двух
|
# структурному (scraper_kit...yandex.detail.DETAIL_CONTACTS_MARKERS); любой из двух
|
||||||
# даёт отказ, объявление остаётся в очереди (detail_enriched_at не проставляется).
|
# даёт отказ, объявление остаётся в очереди (detail_enriched_at не проставляется).
|
||||||
# ENV: YANDEX_DETAIL_MIN_HTML_BYTES.
|
# ENV: YANDEX_DETAIL_MIN_HTML_BYTES.
|
||||||
yandex_detail_min_html_bytes: int = 1_000_000
|
yandex_detail_min_html_bytes: int = 1_000_000
|
||||||
|
|
|
||||||
|
|
@ -467,8 +467,10 @@ async def run_yandex_detail_backfill(
|
||||||
)
|
)
|
||||||
if consecutive_none >= max_consecutive_blocks:
|
if consecutive_none >= max_consecutive_blocks:
|
||||||
logger.error(
|
logger.error(
|
||||||
|
# consecutive_none смешанный (фетч-ошибка + parse-None +
|
||||||
|
# недогруз) — «недогруженных» назвало бы только один вклад.
|
||||||
"yandex_detail_backfill: run_id=%d ABORT -- %d подряд "
|
"yandex_detail_backfill: run_id=%d ABORT -- %d подряд "
|
||||||
"недогруженных страниц. enriched=%d attempted=%d",
|
"без обогащения. enriched=%d attempted=%d",
|
||||||
run_id,
|
run_id,
|
||||||
consecutive_none,
|
consecutive_none,
|
||||||
counters.enriched,
|
counters.enriched,
|
||||||
|
|
|
||||||
|
|
@ -140,3 +140,19 @@ def test_reason_names_the_two_signals() -> None:
|
||||||
# Размерный: контакты есть, а страница обрезана.
|
# Размерный: контакты есть, а страница обрезана.
|
||||||
reason = detail_incomplete_reason(f'"{CONTACTS_MARKER}":[]', min_html_bytes=1_000_000)
|
reason = detail_incomplete_reason(f'"{CONTACTS_MARKER}":[]', min_html_bytes=1_000_000)
|
||||||
assert reason is not None and "недогружена" in reason
|
assert reason is not None and "недогружена" in reason
|
||||||
|
|
||||||
|
|
||||||
|
def test_redirect_phones_alone_counts_as_complete() -> None:
|
||||||
|
"""Карточка «без телефона / только чат»: redirectPhones есть, encryptedPhones нет.
|
||||||
|
|
||||||
|
Класс в замер #3192 не попадал (там у всех 12 были оба ключа). Требуя именно
|
||||||
|
encryptedPhones, мы браковали бы такие карточки вечно — они возвращаются в очередь,
|
||||||
|
а ключ у них не появится. Маркеры литералами: правку снимут — тест обязан краснеть
|
||||||
|
по значению («карточка отбракована»), а не по ImportError.
|
||||||
|
"""
|
||||||
|
from scraper_kit.providers.yandex.detail import detail_incomplete_reason
|
||||||
|
|
||||||
|
body = "<html>" + "x" * 3_920_119
|
||||||
|
assert detail_incomplete_reason(body + '"redirectPhones":["a"]</html>') is None
|
||||||
|
# Фальсификация: без ОБОИХ ключей та же страница полного размера — недогруз.
|
||||||
|
assert detail_incomplete_reason(body + "</html>") is not None
|
||||||
|
|
|
||||||
|
|
@ -50,11 +50,14 @@ logger = logging.getLogger(__name__)
|
||||||
# offer 52275656 3 920 119 б encryptedPhones 65
|
# offer 52275656 3 920 119 б encryptedPhones 65
|
||||||
# offer 62983459 1 805 556 б encryptedPhones 0 <- недогруз
|
# offer 62983459 1 805 556 б encryptedPhones 0 <- недогруз
|
||||||
# offer 12108408 4 732 884 б encryptedPhones 65
|
# offer 12108408 4 732 884 б encryptedPhones 65
|
||||||
# Ключ выбран так, чтобы он был у ПОЛНЫХ карточек в том же режиме, в каком мы ходим:
|
# Ключи выбраны так, чтобы они были у ПОЛНЫХ карточек в том же режиме, в каком мы ходим:
|
||||||
# `encryptedPhones` отдаётся и анонимной сессии (app/services/yandex_session.py и
|
# оба отдаются и анонимной сессии (app/services/yandex_session.py и миграция 274 — с
|
||||||
# миграция 274 — с куками и без есть encryptedPhones + redirectPhones, отличается
|
# куками и без есть encryptedPhones + redirectPhones, отличается только mainPhone,
|
||||||
# только mainPhone, поэтому mainPhone признаком полноты быть не может).
|
# поэтому mainPhone признаком полноты быть не может).
|
||||||
DETAIL_CONTACTS_MARKER = "encryptedPhones"
|
# Достаточно ЛЮБОГО из двух: замером #3192 покрыты 12 карточек, у всех были оба ключа,
|
||||||
|
# но класс «без телефона / только чат» в замер не попал. Требуя encryptedPhones, мы
|
||||||
|
# браковали бы такие карточки ВЕЧНО (в очередь они возвращаются, а ключ не появится).
|
||||||
|
DETAIL_CONTACTS_MARKERS = ("encryptedPhones", "redirectPhones")
|
||||||
|
|
||||||
# Второй, независимый признак. Полная карточка — 3-5 МБ; порог держим заметно ниже
|
# Второй, независимый признак. Полная карточка — 3-5 МБ; порог держим заметно ниже
|
||||||
# наблюдавшегося недогруза (1,8 МБ), потому что размер зависит от объявления. Он ловит
|
# наблюдавшегося недогруза (1,8 МБ), потому что размер зависит от объявления. Он ловит
|
||||||
|
|
@ -74,8 +77,9 @@ def detail_incomplete_reason(
|
||||||
"""
|
"""
|
||||||
if not html:
|
if not html:
|
||||||
return "empty html"
|
return "empty html"
|
||||||
if DETAIL_CONTACTS_MARKER not in html:
|
if not any(marker in html for marker in DETAIL_CONTACTS_MARKERS):
|
||||||
return f"нет блока контактов ({DETAIL_CONTACTS_MARKER} отсутствует), {len(html)} б"
|
markers = "/".join(DETAIL_CONTACTS_MARKERS)
|
||||||
|
return f"нет блока контактов ({markers} отсутствуют), {len(html)} б"
|
||||||
if len(html) < min_html_bytes:
|
if len(html) < min_html_bytes:
|
||||||
return f"страница недогружена: {len(html)} б < {min_html_bytes} б"
|
return f"страница недогружена: {len(html)} б < {min_html_bytes} б"
|
||||||
return None
|
return None
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue