Real production state: **0/9302 (100%)** Avito listings имели NULL
listing_date. Audit показал regex matched только relative numeric
("5 дней назад") — Avito SERP сейчас использует:
- Keyword shortcuts «сегодня в 12:30», «вчера в 18:45», «позавчера», «только что»
- Absolute «18 мая», «5 июня в 12:30» (year inferred — current, или
rollback к прошлому году если month в будущем больше чем на 30d)
Changes:
- Expand _parse_relative_date():
* keyword check first (без \d+ regex match)
* relative numeric (existing) — без изменений
* absolute date regex с _RU_MONTHS dict + roll-back на prev year heuristic
Tests: 10/10 pass (4 existing + 6 new). Ruff clean.
Impact: 9302 Avito listings + new daily scrapes теперь будут иметь
listing_date. Это **прямо повысит linkage rate в /sales-vs-listings**
(PR K) с current ~5% до 30%+ (теоретически до 80% при listing_date
плотности).
Existing 9302 NULL — будут пересобраны при следующем full sweep после
deploy. Backfill detail page для each — отдельный operation скрипт
(out of scope, можно через docker exec ad-hoc).
Refs #564 (linkage rate improvement).
69 lines
2.5 KiB
Python
69 lines
2.5 KiB
Python
from datetime import date, timedelta
|
||
|
||
from app.services.scrapers.avito import _parse_relative_date
|
||
|
||
|
||
def test_days_ago():
|
||
assert _parse_relative_date("5 дней назад") == date.today() - timedelta(days=5)
|
||
|
||
|
||
def test_week_ago():
|
||
assert _parse_relative_date("2 недели назад") == date.today() - timedelta(days=14)
|
||
|
||
|
||
def test_hour_ago_is_today():
|
||
assert _parse_relative_date("3 часа назад") == date.today()
|
||
|
||
|
||
def test_none_passthrough():
|
||
assert _parse_relative_date(None) is None
|
||
assert _parse_relative_date("") is None
|
||
assert _parse_relative_date("random text") is None
|
||
|
||
|
||
# Keyword shortcuts — без \d+ (Avito SERP формат для свежих cards)
|
||
def test_today_keyword():
|
||
assert _parse_relative_date("сегодня в 12:30") == date.today()
|
||
|
||
|
||
def test_yesterday_keyword():
|
||
assert _parse_relative_date("вчера в 18:45") == date.today() - timedelta(days=1)
|
||
|
||
|
||
def test_day_before_yesterday():
|
||
assert _parse_relative_date("позавчера") == date.today() - timedelta(days=2)
|
||
|
||
|
||
def test_just_now():
|
||
assert _parse_relative_date("только что") == date.today()
|
||
|
||
|
||
# Absolute dates — «18 мая», «5 июня в 12:30»
|
||
def test_absolute_date_recent():
|
||
today = date.today()
|
||
# Take a day-month combo near current (last month) — gradening для CI stability
|
||
if today.month >= 2:
|
||
target = date(today.year, today.month - 1, 15)
|
||
else:
|
||
target = date(today.year - 1, 12, 15)
|
||
ru_months = {
|
||
1: "января", 2: "февраля", 3: "марта", 4: "апреля",
|
||
5: "мая", 6: "июня", 7: "июля", 8: "августа",
|
||
9: "сентября", 10: "октября", 11: "ноября", 12: "декабря",
|
||
}
|
||
text = f"{target.day} {ru_months[target.month]} в 12:30"
|
||
assert _parse_relative_date(text) == target
|
||
|
||
|
||
def test_absolute_date_future_month_rolls_back():
|
||
"""Если today январь, а текст «5 декабря» — это прошлый год."""
|
||
today = date.today()
|
||
if today.month == 1:
|
||
# Today already January, «декабря» → previous year December
|
||
result = _parse_relative_date("5 декабря")
|
||
assert result == date(today.year - 1, 12, 5)
|
||
else:
|
||
# Skip when not January — would change semantics
|
||
result = _parse_relative_date("5 января")
|
||
# Either matches current year January (если уже прошло) или previous
|
||
assert result is not None and result.month == 1 and result.day == 5
|