fix(scrapers): narrow domrf Level-1 status badge-class regex (#1609 follow-up) #1704

Merged
lekss361 merged 1 commit from fix/domrf-badge-regex-narrow-1686 into main 2026-06-17 18:34:33 +00:00
2 changed files with 31 additions and 1 deletions

View file

@ -80,7 +80,12 @@ _STATUS_KW_RE = re.compile(
re.IGNORECASE | re.UNICODE,
)
# CSS-классы, характерные для статус-бейджей в Next.js/Tailwind.
_STATUS_BADGE_CLS_RE = re.compile(r"status|badge|tag|chip|label", re.IGNORECASE)
# Требуем слово «status» как отдельный токен внутри hyphen-separated CSS-класса
# (напр. «status-badge», «flat-status-tag», «object-status»).
# Предыдущий паттерн «status|badge|tag|chip|label» был слишком широк —
# срабатывал на любой generic элемент с классом «tag»/«chip»/«label»/«badge»,
# не имеющим отношения к статусу продажи (#1609 follow-up, #1686).
_STATUS_BADGE_CLS_RE = re.compile(r"(?<![a-z])status(?![a-z])", re.IGNORECASE)
def _classify_status_kw(matched_text: str) -> str | None:

View file

@ -211,6 +211,31 @@ def test_prodana_feminine_classified_as_sold() -> None:
assert result.get("status") == STATUS_SOLD
def test_generic_label_tag_not_treated_as_badge() -> None:
"""Элемент с классом 'label' или 'tag' (без слова 'status') НЕ должен
активировать Уровень 1 (#1686 follow-up: regex был слишком широк).
Страница: generic <span class="label"> с текстом 'В продаже' в шапке,
реальный статус-бейдж с классом 'status-badge' содержит 'Продана'.
Уровень 1 должен выбрать только блок status-badge, а не label-шапку.
"""
html = (
"<!doctype html><html><body>"
# generic label в шапке — НЕ должен активировать Level-1 badge match
'<span class="label">В продаже</span>'
'<span class="tag">Новостройка</span>'
'<span class="chip">ЕКБ</span>'
'<span class="badge">Акция</span>'
# настоящий статус-бейдж — должен быть подхвачен Level-1
'<div class="status-badge">Продана</div>'
"</body></html>"
)
result = parse_catalog_flat(html)
# Level-1 должен взять status-badge (Продана → sold),
# generic label/tag/chip/badge не должны перебить правильный результат
assert result.get("status") == STATUS_SOLD
def test_full_page_sold_flat_no_false_free() -> None:
"""Реалистичный HTML проданной квартиры: навигация 'в продаже', бейдж 'продано'."""
html = (