feat(tradein-sweep): --require-house-number filter (default on)

Yandex valuation endpoint resolves only to specific buildings; bare street
names like 'Академическая улица' return 0 items. Filter to addresses with a
house number (regex ', \d+') cuts the work pool from 583 to ~123 addresses
that actually have history data. Toggle with --no-require-house-number to
sweep everything.
This commit is contained in:
lekss361 2026-05-24 17:59:09 +03:00
parent bc594e3f79
commit 5ee8a20732

View file

@ -69,22 +69,34 @@ def _addresses_to_sweep(
limit: int | None,
skip_recent_days: int,
single_address: str | None,
require_house_number: bool = True,
) -> list[str]:
"""Pull unique active EKB yandex addresses, optionally skipping recently-cached ones."""
"""Pull unique active EKB yandex addresses, optionally skipping recently-cached ones.
require_house_number: filter to addresses containing a house number. Yandex's
valuation endpoint needs a specific building bare street names ('Академическая
улица') return 0 items. Heuristic: address must contain a digit after a comma
OR end with a digit token. Default True.
"""
if single_address:
return [single_address.strip()]
# Postgres regex for house-number tokens — used when require_house_number=True.
# Matches ", 12" / ", 12к3" / ", 5Б" anywhere in the address.
house_num_clause = " AND address ~ ',\\s*\\d+' " if require_house_number else ""
db = SessionLocal()
try:
if skip_recent_days > 0:
sql = text(
"""
f"""
SELECT DISTINCT l.address
FROM listings l
WHERE l.source = 'yandex'
AND l.region_code = 66
AND l.is_active = TRUE
AND l.address IS NOT NULL
{house_num_clause}
AND NOT EXISTS (
SELECT 1 FROM external_valuations ev
WHERE ev.source = 'yandex_valuation'
@ -97,13 +109,14 @@ def _addresses_to_sweep(
rows = db.execute(sql, {"days": skip_recent_days}).mappings().all()
else:
sql = text(
"""
f"""
SELECT DISTINCT address
FROM listings
WHERE source = 'yandex'
AND region_code = 66
AND is_active = TRUE
AND address IS NOT NULL
{house_num_clause}
ORDER BY address
"""
)
@ -213,9 +226,29 @@ async def main() -> None:
default=None,
help="Single address mode — sweep only this address",
)
p.add_argument(
"--require-house-number",
dest="require_house_number",
action="store_true",
default=True,
help="Skip addresses without a house number (default: True). "
"Yandex valuation endpoint needs a specific building; street-only addresses "
"return 0 items. Use --no-require-house-number to disable.",
)
p.add_argument(
"--no-require-house-number",
dest="require_house_number",
action="store_false",
help="Include all addresses (sweep street-only entries too — most return 0).",
)
args = p.parse_args()
addresses = _addresses_to_sweep(args.limit, args.skip_recent_days, args.address)
addresses = _addresses_to_sweep(
args.limit,
args.skip_recent_days,
args.address,
require_house_number=args.require_house_number,
)
if not addresses:
print("No addresses to sweep (all recently cached or none match query).", flush=True)
return