Avito leaks addresses with house number glued to district marker without separator («…Савкова, 29р-н Академический»), breaking house-number extraction and same-house matching (41 unmatched avito listings on one street). _clean_address now inserts ", " between a house-number token (digits + optional Cyrillic letter + optional /N|сN|кN|корпус|стр) and a following marker (р-н, мкр, район, г., пос, снт, …). - avito.py: idempotent _deglue_house_marker step (CSS/tail-strip kept) - tests: de-glue positive/negative/idempotency (24 passed) - data/sql/124_deglue_avito_addresses.sql: idempotent backfill for stored rows normalize.py НЕ тронут (общий fingerprint матчинга, #1534). Закрывает avito-часть #1773 (cian-без-номера + дедуп — отдельно, зона cian).
82 lines
3.6 KiB
Python
82 lines
3.6 KiB
Python
import pytest
|
||
|
||
from app.services.scrapers.avito import _clean_address
|
||
|
||
|
||
def test_strips_css_noise():
|
||
raw = (
|
||
"ул. Токарей, 56к1Площадь 1905 года.css-39hgr0{fill:currentColor;"
|
||
"height:1em;box-sizing:border-box;}.css-39hgr0:focus{outline:none;}"
|
||
"от 31 мин.Геологическая.css-39hgr0{...}"
|
||
)
|
||
assert _clean_address(raw) == "ул. Токарей, 56к1"
|
||
|
||
|
||
def test_clean_address_passthrough():
|
||
assert _clean_address("ул. Малышева, 1") == "ул. Малышева, 1"
|
||
|
||
|
||
def test_clean_handles_none():
|
||
assert _clean_address(None) is None
|
||
assert _clean_address("") is None
|
||
assert _clean_address(" ") is None
|
||
|
||
|
||
def test_clean_strips_trailing_punctuation():
|
||
assert _clean_address("ул. Ленина, 5,") == "ул. Ленина, 5"
|
||
|
||
|
||
# ── #1773: де-слип номера дома и маркера района/нас.пункта ────────────────────
|
||
@pytest.mark.parametrize(
|
||
"raw,expected",
|
||
[
|
||
# реальный кейс с прода
|
||
(
|
||
"Свердловская обл., Екатеринбург, ул. Евгения Савкова, 29р-н Академический",
|
||
"Свердловская обл., Екатеринбург, ул. Евгения Савкова, 29, р-н Академический",
|
||
),
|
||
# литера дома слиплась с маркером
|
||
("ул. X, 17Ар-н Пионерский", "ул. X, 17А, р-н Пионерский"),
|
||
("ул. X, 44Бр-н Запад", "ул. X, 44Б, р-н Запад"),
|
||
# корпус через дробь
|
||
("ул. X, 35/2р-н Юг", "ул. X, 35/2, р-н Юг"),
|
||
# корпус через «сN»
|
||
("ул. X, 33с1р-н Центр", "ул. X, 33с1, р-н Центр"),
|
||
# прочие маркеры
|
||
("ул. X, 12мкр Солнечный", "ул. X, 12, мкр Солнечный"),
|
||
("ул. X, 5район Кировский", "ул. X, 5, район Кировский"),
|
||
("ул. X, 100к2р-н Чкаловский", "ул. X, 100к2, р-н Чкаловский"),
|
||
# маркеры населённых пунктов
|
||
("ул. X, 12с. Кашино", "ул. X, 12, с. Кашино"),
|
||
("ул. X, 10д. Малое", "ул. X, 10, д. Малое"),
|
||
("ул. X, 25г. Берёзовский", "ул. X, 25, г. Берёзовский"),
|
||
],
|
||
)
|
||
def test_deglue_house_marker(raw, expected):
|
||
assert _clean_address(raw) == expected
|
||
|
||
|
||
@pytest.mark.parametrize(
|
||
"raw",
|
||
[
|
||
# уже расклеено — идемпотентность
|
||
"ул. Евгения Савкова, 29, р-н Академический",
|
||
# нормальные адреса без склейки — разделять НЕ надо
|
||
"ул. Малышева, 1",
|
||
"ул. Токарей, 56к1",
|
||
"ул. Ленина, 5",
|
||
"ул. Серова, 45",
|
||
"г. Екатеринбург, ул. Ленина, 10",
|
||
"снт Дружба, уч. 12",
|
||
"ул. Декабристов, 16",
|
||
],
|
||
)
|
||
def test_deglue_negative_no_change(raw):
|
||
# для этих строк де-слип не должен ничего менять (кроме штатного strip пунктуации)
|
||
assert _clean_address(raw) == raw.strip(" ,.\n\t")
|
||
|
||
|
||
def test_deglue_idempotent():
|
||
once = _clean_address("ул. Евгения Савкова, 29р-н Академический")
|
||
twice = _clean_address(once)
|
||
assert once == twice == "ул. Евгения Савкова, 29, р-н Академический"
|