From d03c96a79aa4d1c6e570cfb2635b21b3d2e06982 Mon Sep 17 00:00:00 2001 From: bot-backend Date: Sat, 30 May 2026 19:35:13 +0300 Subject: [PATCH] =?UTF-8?q?fix(scrapers):=20yandex=20area=20=D0=B8=D0=B7?= =?UTF-8?q?=20embedded-state=20JSON=20(Refs=20#775)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Часть A (#24): yandex_realty.py парсил площадь из RAW-HTML (regex), пустого до JS-гидрации → 82% NULL area. _parse_html теперь извлекает {offer_id: area_m2} из + +
+ Открыть + +
{price_fmt} ₽
+
+""" + + +def test_area_from_state_json_no_dom_text(): + """area_m2 extracted from embedded JSON state when DOM text has no area.""" + html = _make_yandex_state_html(offer_id="1234567890", area=63.5) + s = YandexRealtyScraper() + lots = s._parse_html(html, page=0) + assert len(lots) == 1 + assert lots[0].area_m2 == pytest.approx(63.5) + + +def test_area_from_state_json_multiple_offers(): + """State with multiple offers — each card gets its own area from state.""" + state = { + "offers": [ + {"offerId": "111", "totalArea": 42.0}, + {"offerId": "222", "totalArea": 78.3}, + ] + } + state_json = json.dumps(state) + html = f""" + + +
+ x +
3 000 000 ₽
+
+
+ x +
5 000 000 ₽
+
+""" + s = YandexRealtyScraper() + lots = s._parse_html(html, page=0) + assert len(lots) == 2 + areas = {lot.source_id: lot.area_m2 for lot in lots} + assert areas["111"] == pytest.approx(42.0) + assert areas["222"] == pytest.approx(78.3) + + +def test_area_dom_fallback_when_no_state(): + """When state script absent, area falls back to DOM regex (existing behavior).""" + # SINGLE_CARD_HTML has area in DOM text — state script absent + s = YandexRealtyScraper() + lots = s._parse_html(SINGLE_CARD_HTML, page=0) + assert len(lots) == 1 + assert lots[0].area_m2 == pytest.approx(36.8) + + +def test_extract_offer_areas_from_state_nested_path(): + """State via pageData.offers path (SERP v2 shape).""" + state = { + "pageData": { + "offers": [ + {"offerId": "999", "spaceTotal": 55.0}, + ] + } + } + html = '" + areas = _extract_offer_areas_from_state(html) + assert areas == {"999": 55.0} + + +def test_extract_offer_areas_area_dict_value(): + """area field as nested dict {'value': 48.0, 'unit': 'SQM'} (some Yandex responses).""" + state = { + "offers": [ + {"offerId": "777", "area": {"value": 48.0, "unit": "SQM"}}, + ] + } + html = '" + areas = _extract_offer_areas_from_state(html) + assert areas == {"777": 48.0} + + +def test_extract_offer_areas_empty_when_no_script(): + """No state script → empty dict returned, no crash.""" + html = "

no state here

" + areas = _extract_offer_areas_from_state(html) + assert areas == {}