fix(avito): classify novostroyki by item-development-name marker; map переуступка sale_type #1716
4 changed files with 61 additions and 15 deletions
|
|
@ -74,15 +74,7 @@ _UNIT_DAYS: dict[str, int] = {
|
|||
# поэтому отдельная ветка с неявным n=1. Юниты в винительном падеже («минуту»,
|
||||
# «неделю») плюс именительный («час», «день»).
|
||||
_REL_DATE_SINGULAR_RE = re.compile(
|
||||
r"(?P<unit>"
|
||||
r"секунду|"
|
||||
r"минуту|"
|
||||
r"час|"
|
||||
r"день|"
|
||||
r"неделю|"
|
||||
r"месяц|"
|
||||
r"год"
|
||||
r")\s+назад",
|
||||
r"(?P<unit>" r"секунду|" r"минуту|" r"час|" r"день|" r"неделю|" r"месяц|" r"год" r")\s+назад",
|
||||
flags=re.I,
|
||||
)
|
||||
|
||||
|
|
@ -751,12 +743,12 @@ class AvitoScraper(BaseScraper):
|
|||
house_ext_id = parts[-1]
|
||||
house_url = urljoin("https://www.avito.ru", h_href)
|
||||
|
||||
# listing_segment по item URL pattern
|
||||
listing_segment: str | None = None
|
||||
if "/kvartiry/" in href:
|
||||
listing_segment = "vtorichka"
|
||||
elif "/novostroyki/" in href:
|
||||
listing_segment = "novostroyki"
|
||||
# listing_segment по DOM-маркеру карточки: новостройки несут
|
||||
# data-marker="item-development-name" (название ЖК/застройщика),
|
||||
# вторичка — нет. URL-паттерн ненадёжен: каждый avito-URL квартиры
|
||||
# содержит /kvartiry/ (вкл. новостройки) → ветка всегда vtorichka.
|
||||
dev_name = card.css_first('[data-marker="item-development-name"]')
|
||||
listing_segment = "novostroyki" if dev_name is not None else "vtorichka"
|
||||
|
||||
return ScrapedLot(
|
||||
source="avito",
|
||||
|
|
|
|||
|
|
@ -152,6 +152,7 @@ _SALE_TYPE_MAP: dict[str, str] = {
|
|||
"свободная": "free",
|
||||
"альтернатива": "alternative",
|
||||
"аукцион": "auction",
|
||||
"переуступка": "assignment",
|
||||
}
|
||||
|
||||
_HOUSE_TYPE_MAP: dict[str, str] = {
|
||||
|
|
|
|||
|
|
@ -78,6 +78,25 @@ def test_minimal_parse() -> None:
|
|||
assert result.views_today == 12
|
||||
|
||||
|
||||
def test_sale_type_assignment_pereustupka() -> None:
|
||||
"""«Способ продажи: переуступка» → sale_type='assignment' (ДДУ переуступка,
|
||||
сигнал новостройки). До фикса map не содержал ключ → None."""
|
||||
html = """
|
||||
<html><body>
|
||||
<div data-marker="item-view/item-id">№ 8043003287</div>
|
||||
<span itemprop="price" content="9500000">9 500 000 ₽</span>
|
||||
<div data-marker="item-view/item-params">
|
||||
<ul>
|
||||
<li>Количество комнат: 2</li>
|
||||
<li>Способ продажи: переуступка</li>
|
||||
</ul>
|
||||
</div>
|
||||
</body></html>
|
||||
"""
|
||||
result = parse_detail_html(html, "https://www.avito.ru/test_8043003287")
|
||||
assert result.sale_type == "assignment"
|
||||
|
||||
|
||||
def test_metro_extraction() -> None:
|
||||
result = parse_detail_html(MINIMAL_HTML, SOURCE_URL)
|
||||
# "Чкаловская 11-15 мин пешком" → metro_stations
|
||||
|
|
|
|||
|
|
@ -60,3 +60,37 @@ def test_lazy_card_date_comes_from_json_not_dom() -> None:
|
|||
lots = AvitoScraper()._parse_html(html, "https://www.avito.ru/x")
|
||||
lazy = next(lot for lot in lots if "8043936560" in (lot.source_url or ""))
|
||||
assert lazy.listing_date == _expected(_TS_LAZY)
|
||||
|
||||
|
||||
# ── listing_segment по DOM-маркеру item-development-name ───────────────────────
|
||||
# Каждый avito-URL квартиры содержит /kvartiry/ (вкл. новостройки), поэтому
|
||||
# сегмент определяется не по URL, а по наличию data-marker="item-development-name"
|
||||
# (название ЖК/застройщика рендерится только у карточек новостроек).
|
||||
|
||||
|
||||
def _serp_card(item_id: str, *, with_dev_name: bool) -> str:
|
||||
dev = '<div data-marker="item-development-name">ЖК «Федерация»</div>' if with_dev_name else ""
|
||||
return f"""
|
||||
<div data-marker="item" data-item-id="{item_id}">
|
||||
<a data-marker="item-title" href="/ekaterinburg/kvartiry/2-k_kvartira_{item_id}">
|
||||
2-к. квартира, 50 м², 5/20 эт.</a>
|
||||
<meta itemprop="price" content="9500000"/>
|
||||
{dev}
|
||||
</div>
|
||||
"""
|
||||
|
||||
|
||||
def test_segment_novostroyki_when_development_name_present() -> None:
|
||||
"""Карточка с data-marker='item-development-name' → listing_segment='novostroyki'."""
|
||||
html = f"<html><body>{_serp_card('8043003287', with_dev_name=True)}</body></html>"
|
||||
lots = AvitoScraper()._parse_html(html, "https://www.avito.ru/ekaterinburg/kvartiry")
|
||||
assert len(lots) == 1
|
||||
assert lots[0].listing_segment == "novostroyki"
|
||||
|
||||
|
||||
def test_segment_vtorichka_when_no_development_name() -> None:
|
||||
"""Карточка без маркера ЖК → listing_segment='vtorichka' (даже с /kvartiry/ в URL)."""
|
||||
html = f"<html><body>{_serp_card('8043936560', with_dev_name=False)}</body></html>"
|
||||
lots = AvitoScraper()._parse_html(html, "https://www.avito.ru/ekaterinburg/kvartiry")
|
||||
assert len(lots) == 1
|
||||
assert lots[0].listing_segment == "vtorichka"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue