

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


- 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.
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
Normalización
Parsers por portal, municipio y precisión de la ubicación.
194 municipiosFiltros
- 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 v2PostgreSQL + 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 cerradoCola de alertas
Deduplicación, horas de silencio, tope por hora y reintentos.
Salidas
- Telegram
- ntfy
- Panel web con mapa
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
- Python
- FastAPI
- Pydantic
- asyncpg
- Jinja2
- asyncio
- aiohttp
- BeautifulSoup
- IMAP
- RSS
- PostgreSQL
- PostGIS
- MapLibre
- React 19
- Vite
- TypeScript
- Docker Compose
- GitHub Actions
- pytest
- Uptime Kuma
- 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.