Saltar al contenido
rubén.garcía
Todos los proyectos
Logo de Inmo-SniperLogo de Inmo-Sniper

Inmo-Sniper

Radar inmobiliario autoalojado. Rastrea portales cada pocos minutos, descarta anuncios trampa, puntúa cada vivienda frente al precio de referencia de su municipio y solo avisa cuando algo merece la pena.

Rol
Coautor en equipo de dos · ~2/3 de los commits
Estado
Beta privada con varias cuentas
Despliegue
Mini-PC propio · Docker Compose
Código
Repositorio privado · acceso bajo petición
Panel de Inmo-Sniper con la lista de viviendas de ejemplo puntuadas a la izquierda y el mapa del área metropolitana de Bilbao con los anuncios agrupados.Panel de Inmo-Sniper con la lista de viviendas de ejemplo puntuadas a la izquierda y el mapa del área metropolitana de Bilbao con los anuncios agrupados.
municipios vigilados, cada uno con su referencia de mercado
194
tests, con CI sobre PostGIS real
~386
fuentes de anuncios: 3 portales y el RSS de vivienda protegida
4
notas por vivienda: para vivir y para alquilar
2

El problema

Buscar vivienda en Bizkaia significa recibir decenas de alertas al día de portales distintos. La mayoría son ruido o, peor, trampas: pisos okupados, nuda propiedad, proindivisos o subastas con un precio que parece una ganga. Las que de verdad lo son desaparecen en horas.

Inmo-Sniper junta varios portales en un solo radar, descarta las trampas leyendo el texto, incluida la negación («libre de okupas» no es un problema), compara cada precio con una referencia de mercado de su municipio y solo avisa por Telegram cuando la vivienda supera los umbrales de quien la busca, ya sea para vivir o para alquilar.

En funcionamientoCapturas del proyecto real con datos de ejemplo.

Landing pública
Móvil
Alerta de TelegramRecreación
Estadísticas
Filtros
Nuevo radar por zona

Cómo funcionaPor dónde pasa cada dato, de la entrada a la salida.

Ingesta

  • Rastreo directo de portales
  • Correos de alerta vía IMAP
  • RSS de vivienda protegida
robots.txt · backoff

Normalización

Parsers por portal, municipio y precisión de la ubicación.

194 municipios

Filtros

  • Trampas, con negación
  • Tipo de inmueble
  • Cifras inverosímiles

Mercado y nota

Referencia en cascada y dos notas: para vivir y para alquilar.

motor v2

PostgreSQL + PostGIS

Puntos geográficos con índice espacial y procedencia de cada dato.

Regla de alerta

Una sola definición, en Python y en SQL, probada una contra otra.

falla cerrado

Cola de alertas

Deduplicación, horas de silencio, tope por hora y reintentos.

Salidas

  • Telegram
  • ntfy
  • Panel web con mapa
Decisión: qué merece una alertaLo que ve quien buscaCada ronda termina con un latido a Uptime Kuma

Decisiones técnicasProblemas que aparecieron y cómo se resolvieron.

Una sola definición de «ganga», en Python y en SQL

La regla que decide si algo se alerta existe en Python y en SQL, y un test compara ambas sobre las mismas filas de PostgreSQL con casos frontera y aleatorios. Nació de un bug real que reapareció cuatro veces. Falla cerrado, porque solo alerta con confianza de mercado alta o media.

Referencia de mercado que se autocalibra

El precio de referencia se busca en cascada, del barrio curado al dato oficial del municipio, luego la mediana propia de lo rastreado (desde 8 muestras) y por último una estimación. La media nacional se usa como último recurso y nunca dispara una alerta. Cada inmueble guarda con qué fuente se puntuó.

Un rastreo que no satura los portales

User-Agent honesto y parser propio de robots.txt conforme a la RFC 9309. Al primer 403, 429 o 503 abandona ese portal durante la ronda, con enfriamiento creciente de 1 h a 12 h, y solo pide la ficha de anuncios nuevos o con cambio de precio. Pasó de 154 a 5–21 peticiones por ronda.

Retirar un portal antes que sortear su bloqueo

Un portal lo prohíbe en sus condiciones y su robots.txt, y respondía con captcha. En lugar de esquivarlo, sus anuncios entran por los correos de alerta que el propio portal envía.

Detectar el silencio

Si un portal cambia su HTML, el parser devuelve cero anuncios y nada parece roto. Cada ronda manda un latido a Uptime Kuma que avisa de rondas vacías o portales mudos, y la ausencia de latidos delata un worker caído.

Cuentas y cobros

Argon2, rate limiting en base de datos por email e IP, comprobación de mismo origen en cada mutación y aislamiento entre usuarios probado con tests. Webhooks de Stripe con firma verificada, idempotencia por evento, orden resuelto por fecha y bloqueo de fila contra suscripciones duplicadas.

Tecnologías

Backend
  • Python
  • FastAPI
  • Pydantic
  • asyncpg
  • Jinja2
Worker
  • asyncio
  • aiohttp
  • BeautifulSoup
  • IMAP
  • RSS
Datos
  • PostgreSQL
  • PostGIS
Interfaz
  • MapLibre
  • React 19
  • Vite
  • TypeScript
Operación
  • Docker Compose
  • GitHub Actions
  • pytest
  • Uptime Kuma
Integraciones
  • Telegram
  • ntfy
  • Stripe

Próximos pasos

  • Migración del panel a una SPA con React 19, Vite y TypeScript, ya en marcha.
  • Conectar el cliente del Catastro, que existe pero aún no está en ningún flujo.
Siguiente proyectoJarvis