En resumen: Redfin expone puntos finales de API ocultos que devuelven datos en formato JSON estructurado para los anuncios inmobiliarios, lo que permite evitar por completo el frágil análisis de HTML. Esta guía te explica paso a paso cómo crear un rastreador en Python que extraiga datos de alquileres y ventas, realice búsquedas por ubicación, supervise los nuevos anuncios a través de mapas de sitio XML y exporte resultados limpios a CSV o JSON.
Introducción: ¿Por qué extraer datos de propiedades de Redfin?
Redfin es una de las plataformas inmobiliarias más grandes de Estados Unidos, con millones de anuncios residenciales en prácticamente todas las áreas metropolitanas. Si necesitas extraer datos de Redfin para realizar análisis de mercado, estudios de inversión o crear una base de datos de propiedades, la arquitectura interna de la plataforma juega a tu favor. A diferencia de los sitios que renderizan todo del lado del servidor, el front-end de Redfin extrae datos de puntos de conexión API ocultos que devuelven JSON bien estructurado. Eso significa que puedes extraer datos de propiedades mediante programación sin tener que lidiar con selectores CSS que fallan cada vez que el sitio actualiza su diseño.
En este tutorial, crearás desde cero un rastreador de Redfin basado en Python. Abordaremos tres objetivos de scraping distintos (anuncios de alquiler, propiedades en venta y resultados de búsqueda), te mostraremos cómo supervisar las propiedades recién anunciadas a través de los mapas de sitio XML de Redfin y te guiaremos en la exportación de tus datos tanto a CSV como a JSON. A lo largo del proceso, trataremos la limitación de velocidad, las protecciones contra bots y las consideraciones legales que debes tener en cuenta antes de ejecutar cualquier proyecto de web scraping inmobiliario a gran escala.
Campos de datos de Redfin que puedes extraer
Antes de escribir cualquier código, es útil saber qué es lo que Redfin realmente expone. La plataforma organiza la información de las propiedades en varias categorías, y conocer los campos de datos disponibles te ayudará a planificar a qué puntos de conexión dirigirte y cómo debería ser tu esquema de salida.
A continuación, te ofrecemos una referencia de los principales objetivos de scraping y los campos que puedes esperar:
|
Objetivo de scraping |
Campos de datos clave |
|---|---|
|
Anuncios de venta |
Precio de venta, historial de ventas, precio por metro cuadrado, dormitorios, baños, superficie, tamaño del terreno, año de construcción, cuotas de la comunidad de propietarios, tipo de propiedad, número MLS, agente inmobiliario |
|
Anuncios de alquiler |
Alquiler mensual, fianza, condiciones del contrato, dormitorios, baños, superficie, política sobre mascotas, servicios, fecha de disponibilidad, administrador de la propiedad |
|
Resultados de búsqueda |
Dirección de la propiedad, URL de la miniatura, estado del anuncio, precio, resumen de dormitorios/baños, días en el mercado, coordenadas |
|
Visitas |
Fechas programadas, franjas horarias, agente inmobiliario, URL de la propiedad asociada |
|
Perfiles de agentes |
Nombre del agente, agencia inmobiliaria, transacciones recientes, valoraciones, área de servicio |
|
Anuncios de terrenos/parcelas |
Superficie, zonificación, precio por acre, servicios públicos disponibles, notas sobre la topografía |
Los puntos finales de alquiler y venta devuelven esquemas JSON diferentes, lo cual es importante a la hora de diseñar su canalización de datos. Los listados de venta incluyen campos como el historial de ventas y métricas de rendimiento del mercado que no aparecen en las respuestas de alquiler, mientras que los datos de alquiler contienen campos específicos del contrato de arrendamiento, como la política sobre mascotas y los requisitos de fianza.
Requisitos previos y configuración del proyecto
Necesitarás Python 3.8 o posterior para este proyecto. Utilizaremos dos bibliotecas principales: httpx para realizar solicitudes HTTP (gestiona bien la asincronía y tiene una API limpia) y parsel para analizar cualquier respuesta HTML o XML, especialmente al trabajar con mapas de sitio.
Crea un directorio de proyecto e instala las dependencias:
mkdir redfin-scraper && cd redfin-scraper
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
pip install httpx parsel
Opcionalmente, añade pandas si quieres una limpieza de datos más avanzada durante la exportación:
pip install pandas
Tu requirements.txt debería tener este aspecto:
httpx>=0.27.0
parsel>=1.9.0
pandas>=2.0.0
Eso es todo lo que necesitas para empezar. Sin bibliotecas de automatización de navegadores, sin Selenium, sin Playwright. Como nos dirigimos directamente a los puntos finales de la API oculta de Redfin, basta con un simple cliente HTTP.
Comprender los puntos finales de la API oculta de Redfin
Cuando cargas una página de propiedades de Redfin en tu navegador, el HTML visible es principalmente una carcasa. Los datos reales de las propiedades se obtienen de forma asíncrona desde puntos finales de API internos. Puedes descubrir estos puntos finales por ti mismo abriendo las DevTools de tu navegador (F12), navegando a la pestaña Red y filtrando por solicitudes «XHR» o «Fetch» mientras se carga una página de anuncios.
Lo que verás es una serie de solicitudes a URL como https://www.redfin.com/stingray/api/home/details/... que devuelven datos estructurados. Las respuestas suelen comenzar con un prefijo de comentario (algo así como {}&&{) seguido de JSON válido. Este prefijo es un patrón de protección contra scripts entre sitios, por lo que tendrás que eliminarlo antes de analizarlo.
Este enfoque «API-first» para el scraping de Redfin tiene ventajas significativas sobre el análisis tradicional de HTML:
- Estabilidad: los nombres de los campos JSON rara vez cambian, mientras que los nombres de las clases CSS pueden variar con cada implementación.
- Exhaustividad: la respuesta de la API suele contener más datos de los que se muestran en la página visible.
- Velocidad: se realiza una sola solicitud por anuncio en lugar de cargar una página completa con imágenes, scripts y hojas de estilo.
- Simplicidad: No es necesaria la automatización del navegador. Un cliente HTTP estándar se encarga de todo.
Para descubrir el punto final adecuado para cualquier tipo de anuncio, carga la página, observa las solicitudes de red y busca aquella que contenga la mayor parte de los datos de la propiedad en su respuesta JSON. El patrón de la URL incluirá identificadores como el ID de la propiedad o una dirección codificada en URL.
Extracción de datos de las páginas de propiedades en alquiler de Redfin
Empecemos con los anuncios de alquiler. Redfin ofrece datos de alquiler a través de una ruta API dedicada que difiere del punto final de venta. Cuando visitas una página de propiedades en alquiler, el navegador realiza una solicitud a un punto final que devuelve todos los detalles del alquiler en formato JSON.
Aquí tienes un ejemplo completo y funcional que recupera un anuncio de alquiler:
import httpx
import json
HEADERS = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/125.0.0.0 Safari/537.36",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.9",
"Referer": "https://www.redfin.com/",
}
def clean_json_response(text: str) -> dict:
"""Strip Redfin's XSS prefix and parse JSON."""
start = text.find("{")
if start == -1:
raise ValueError("No JSON object found in response")
return json.loads(text[start:])
def scrape_rental(url: str) -> dict:
"""Fetch rental property data from Redfin's internal API."""
with httpx.Client(headers=HEADERS, follow_redirects=True) as client:
resp = client.get(url)
resp.raise_for_status()
data = clean_json_response(resp.text)
payload = data.get("payload", {})
rental_info = {
"address": payload.get("streetAddress", {}).get("assembledAddress"),
"rent_price": payload.get("listingPrice"),
"beds": payload.get("beds"),
"baths": payload.get("baths"),
"sqft": payload.get("sqFt"),
"pet_policy": payload.get("petPolicy"),
"amenities": payload.get("amenities", []),
"photos": [p.get("photoUrl") for p in payload.get("photos", [])],
"listing_agent": payload.get("listingAgent", {}).get("name"),
}
return rental_info
# Example usage
listing_url = "https://www.redfin.com/stingray/api/home/details/rental/..."
# result = scrape_rental(listing_url)
# print(json.dumps(result, indent=2))
Hay algunas cosas que hay que tener en cuenta sobre este código. La clean_json_response función gestiona el prefijo XSS que Redfin antepone a las respuestas de la API. Los encabezados imitan una sesión de navegador real, lo cual es importante porque Redfin rechazará las solicitudes que parezcan provenir de un script sin más. La estructura de la respuesta anida los campos más útiles bajo una payload , aunque el anidamiento exacto puede variar dependiendo del tipo de anuncio. Los campos específicos de alquiler como petPolicy y amenities no aparecerán en las respuestas de venta.
Extracción de datos de las páginas de propiedades en venta de Redfin
El punto final de venta sigue un patrón similar, pero el esquema JSON incluye campos adicionales que son exclusivos de los anuncios de compra. Las propiedades en venta incluyen datos históricos de precios, puntuaciones de competitividad en el mercado y registros de valoración fiscal que los anuncios de alquiler simplemente no tienen.
def scrape_for_sale(url: str) -> dict:
"""Fetch for-sale property data from Redfin's internal API."""
with httpx.Client(headers=HEADERS, follow_redirects=True) as client:
resp = client.get(url)
resp.raise_for_status()
data = clean_json_response(resp.text)
payload = data.get("payload", {})
property_info = {
"address": payload.get("streetAddress", {}).get("assembledAddress"),
"list_price": payload.get("listingPrice"),
"price_per_sqft": payload.get("pricePerSqFt"),
"beds": payload.get("beds"),
"baths": payload.get("baths"),
"sqft": payload.get("sqFt"),
"year_built": payload.get("yearBuilt"),
"lot_size": payload.get("lotSize"),
"hoa_dues": payload.get("hoaDues"),
"property_type": payload.get("propertyType"),
"mls_number": payload.get("mlsId"),
"sale_history": payload.get("priceHistory", []),
"tax_history": payload.get("taxHistory", []),
"listing_agent": payload.get("listingAgent", {}).get("name"),
}
return property_info
Las diferencias clave con respecto al rastreador de alquileres son los campos que se extraen. La priceHistory matriz te ofrece un registro cronológico de cada cambio de precio desde que se publicó el anuncio, incluyendo eventos de publicación, en espera y vendidos. El taxHistory campo proporciona los valores catastrales a lo largo del tiempo, lo cual es útil para el análisis de inversiones. Campos como hoaDues y lotSize solo aparecen en los anuncios de venta.
Cuando extraigas datos de venta de Redfin, presta atención al propertyType campo. Este te indica si se trata de una vivienda unifamiliar, un piso, una casa adosada o una vivienda multifamiliar, y esta distinción es importante si estás filtrando los resultados para un segmento de mercado específico.
Extracción de datos de las páginas de resultados de búsqueda de Redfin
Los anuncios individuales son útiles, pero la mayoría de los proyectos de datos inmobiliarios requieren una extracción masiva. La funcionalidad de búsqueda de Redfin también funciona a través de una API interna, que devuelve resultados paginados para una ubicación determinada o un conjunto de filtros.
El punto final de búsqueda acepta parámetros como el ID de la región, el tipo de propiedad, el rango de precios y el desplazamiento de paginación. A continuación te explicamos cómo crear un rastreador de búsqueda:
import time
def scrape_search_results(region_id: str, max_pages: int = 5) -> list:
"""Scrape paginated Redfin search results for a region."""
all_listings = []
with httpx.Client(headers=HEADERS, follow_redirects=True) as client:
for page in range(1, max_pages + 1):
search_url = (
f"https://www.redfin.com/stingray/api/gis?"
f"region_id={region_id}®ion_type=6"
f"&num_homes=350&page={page}"
)
resp = client.get(search_url)
resp.raise_for_status()
data = clean_json_response(resp.text)
homes = data.get("payload", {}).get("homes", [])
if not homes:
break
for home in homes:
listing = {
"address": home.get("streetLine", {}).get("value"),
"city": home.get("city"),
"state": home.get("state"),
"price": home.get("price", {}).get("value"),
"beds": home.get("beds"),
"baths": home.get("baths"),
"sqft": home.get("sqFt", {}).get("value"),
"status": home.get("listingType"),
"days_on_market": home.get("dom"),
"latitude": home.get("latLong", {}).get("latitude"),
"longitude": home.get("latLong", {}).get("longitude"),
"url": home.get("url"),
}
all_listings.append(listing)
# Respectful delay between pages
time.sleep(2)
return all_listings
Necesitarás el region_id para tu área de interés, que puedes encontrar inspeccionando las solicitudes de red cuando realizas una búsqueda en el sitio web de Redfin. El region_type=6 parámetro indica una búsqueda a nivel de ciudad. La paginación se gestiona incrementando el page , y el bucle se detiene cuando la API devuelve un homes .
Fíjate en el time.sleep(2) entre solicitudes. Esto no es opcional si quieres que tu rastreador dure más de unos minutos. Trataremos la limitación de velocidad con más detalle en la sección sobre medidas anti-bot, pero espaciar las solicitudes es lo más importante que puedes hacer para rastrear los resultados de búsqueda de Redfin de forma fiable.
Exportación de datos extraídos a CSV y JSON
Una vez que hayas recopilado los datos de las propiedades, debes convertirlos a un formato utilizable. Tanto CSV como JSON tienen su utilidad: CSV es mejor para el análisis en hojas de cálculo y la importación a bases de datos, mientras que JSON conserva estructuras anidadas como las matrices de historial de ventas.
import csv
def export_to_csv(listings: list, filename: str = "redfin_data.csv"):
"""Export flat listing data to CSV with basic cleaning."""
if not listings:
return
# Normalize price fields: strip $ and commas
for item in listings:
if isinstance(item.get("price"), str):
item["price"] = item["price"].replace("$", "").replace(",", "")
keys = listings[0].keys()
with open(filename, "w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=keys)
writer.writeheader()
writer.writerows(listings)
def export_to_json(listings: list, filename: str = "redfin_data.json"):
"""Export listing data to JSON with indentation."""
with open(filename, "w", encoding="utf-8") as f:
json.dump(listings, f, indent=2, ensure_ascii=False)
Para uso en producción, considera algunos pasos de limpieza de datos antes de la exportación. Estandariza las cadenas de fecha al formato ISO 8601 (YYYY-MM-DD). Convierte las cadenas de precios en números enteros o decimales para que las herramientas posteriores no se bloqueen con los símbolos de moneda. Si estás trabajando con campos anidados como sale_history, aplánalos en columnas separadas para CSV o mantén la estructura anidada en JSON. Usando pandas con json_normalize() puede simplificar este paso de aplanamiento para conjuntos de datos de gran tamaño.
Seguimiento de anuncios nuevos y actualizados mediante mapas de sitio
La mayoría de los tutoriales de scraping de Redfin se limitan a recuperar páginas individuales. Pero si estás creando un proceso de monitorización inmobiliaria, necesitas una forma de descubrir anuncios nuevos y actualizados recientemente de forma automática sin tener que volver a rastrear todo el sitio.
Redfin publica mapas de sitio XML que resuelven este problema. En el momento de escribir este artículo, los feeds relevantes incluyen:
https://www.redfin.com/newest_listings.xmlpara propiedades añadidas recientementehttps://www.redfin.com/sitemap_com_latest_updates.xmlpara anuncios modificados recientemente
A continuación te explicamos cómo analizar estos mapas del sitio e introducir las URL en tu rastreador:
from parsel import Selector
def parse_sitemap(sitemap_url: str) -> list:
"""Extract property URLs and last-modified dates from a Redfin sitemap."""
with httpx.Client(headers=HEADERS) as client:
resp = client.get(sitemap_url)
resp.raise_for_status()
sel = Selector(text=resp.text, type="xml")
sel.remove_namespaces()
entries = []
for url_tag in sel.css("url"):
loc = url_tag.css("loc::text").get()
lastmod = url_tag.css("lastmod::text").get()
entries.append({"url": loc, "last_modified": lastmod})
return entries
# Example: get newest listings
# new_listings = parse_sitemap("https://www.redfin.com/newest_listings.xml")
# for listing in new_listings[:10]:
# print(listing["url"], listing["last_modified"])
La estrategia es sencilla: consulta el mapa del sitio según una programación (diaria u horaria, según tus necesidades), compara las URL y las marcas de tiempo con tu base de datos existente, y extrae solo las entradas nuevas o actualizadas. Este enfoque es mucho más eficiente que el rastreo por fuerza bruta, ya que dejas que Redfin te indique qué ha cambiado en lugar de tener que adivinarlo. Si te interesa extraer mapas de sitio de páginas web de forma más general, la misma técnica de análisis de XML se aplica a casi cualquier sitio que siga el protocolo de mapas de sitio.
Gestión de medidas anti-bot y cómo evitar bloqueos
Redfin emplea varias capas de protección contra el acceso automatizado. Si tu rastreador de Redfin empieza a devolver errores 403 o páginas CAPTCHA, esto es lo que debes comprobar y cómo solucionarlo.
Los encabezados similares a los de un navegador son imprescindibles. Como mínimo, configura un User-Agent, Accept, Accept-Languagey Referer . Nuestros ejemplos de código ya incluyen estos encabezados. Cambia tu cadena de User-Agent periódicamente, ya que un único valor estático en miles de solicitudes es una señal. Entender cómo configurar los encabezados HTTP es fundamental para cualquier proyecto de scraping.
El espaciado entre solicitudes es más importante que los proxies. Antes de invertir en infraestructura de proxies, intenta ralentizar el ritmo. Un retraso de 2 a 5 segundos entre solicitudes te mantendrá por debajo de la mayoría de los umbrales de limitación de velocidad. Implementa un retroceso exponencial en los reintentos: si obtienes un 429 o un 403, espera 30 segundos, luego 60 y luego 120 antes de rendirte.
import random
def polite_delay(base: float = 2.0, jitter: float = 1.5):
"""Sleep with randomized jitter to avoid request pattern detection."""
time.sleep(base + random.uniform(0, jitter))
La rotación de proxies se vuelve necesaria a gran escala. Si necesitas recopilar miles de anuncios, rotar a través de un conjunto de proxies residenciales hace que tus solicitudes parezcan provenir de diferentes usuarios. Las IP de centros de datos tienden a ser marcadas rápidamente en los sitios web inmobiliarios.
La gestión de sesiones también ayuda. Redfin rastrea las cookies a través de las solicitudes, por lo que mantener una sesión (reutilizando la misma httpx.Client instancia) puede, de hecho, reducir las sospechas en comparación con el envío de solicitudes sin estado. Solo asegúrate de iniciar una sesión nueva periódicamente.
Para proyectos de gran volumen, las API de scraping dedicadas pueden gestionar la antidetección, la rotación de proxies y la resolución de CAPTCHA desde un único punto de acceso, lo que te permite centrarte en la lógica de análisis. Los consejos para evitar bloqueos de IP al realizar web scraping se aplican de forma generalizada a todas las plataformas inmobiliarias, no solo a Redfin.
Consideraciones legales y éticas
Antes de ejecutar un scraper de Redfin a una escala significativa, debes comprender el panorama legal. El scraping de datos disponibles públicamente en sitios web suele estar permitido en Estados Unidos, pero hay matices importantes.
En cuanto a la privacidad de los datos, los anuncios inmobiliarios pueden contener información de identificación personal: nombres de vendedores, datos de contacto de agentes y, en ocasiones, números de teléfono. Si almacena o procesa estos datos y presta servicio a usuarios de la UE, se aplican las obligaciones del RGPD independientemente de dónde se encuentren sus servidores. Reduzca la recopilación de información de identificación personal (PII) a lo estrictamente necesario para su caso de uso e implemente políticas de retención.
Por último, plantéate si el scraping es realmente necesario para tu caso de uso. Redfin ofrece un centro de datos que proporciona datos agregados del mercado inmobiliario (precios medios de venta, niveles de inventario, días en el mercado) en forma de archivos CSV descargables gratuitamente. Si necesitas tendencias a nivel de mercado en lugar de anuncios individuales, los datos oficiales pueden ser suficientes.
Puntos clave
- Utilice los puntos finales de la API oculta de Redfin en lugar de analizar el HTML. Las respuestas JSON son más estables, más completas y más rápidas de procesar que el scraping de páginas renderizadas.
- Trata los anuncios de alquiler y venta como modelos de datos independientes. Sus respuestas API contienen campos diferentes, por lo que tu lógica de extracción y tus esquemas de salida deben tener en cuenta ambos.
- Supervisa los mapas del sitio en busca de nuevos anuncios en lugar de volver a rastrear todo el sitio. Realizar sondeos
newest_listings.xmlde forma programada es mucho más eficiente. - Respeta primero los límites de frecuencia y añade proxies después. Un retraso de entre 2 y 5 segundos entre solicitudes evita la mayoría de los bloqueos. Los proxies sirven para escalar, no para sustituir las normas básicas de cortesía.
- Consulte la oferta oficial de datos de Redfin antes de crear un rastreador. Es posible que el Centro de Datos ya disponga de las métricas agregadas que necesita.
Preguntas frecuentes
¿Tiene Redfin una API pública para acceder a los datos de propiedades?
No. Redfin no ofrece una API pública documentada para desarrolladores externos. Los puntos de conexión utilizados en esta guía son API internas a las que el sitio web de Redfin recurre para rellenar sus propias páginas. No están documentadas y pueden cambiar sin previo aviso, por lo que debes crear tu rastreador con un manejo de errores que tenga en cuenta los cambios de esquema.
¿Es legal extraer datos de los anuncios de Redfin?
Extraer datos disponibles públicamente es generalmente legal en EE. UU., pero se encuentra en una zona gris. Los tribunales han dictaminado que acceder a datos web públicos no viola la Ley de Fraude y Abuso Informático, pero infringir los Términos de Servicio de un sitio podría dar lugar a responsabilidad por incumplimiento de contrato. Consulte siempre a un profesional del derecho para casos de uso comercial y nunca extraiga datos protegidos por inicio de sesión sin autorización.
¿Cómo puedo evitar que me bloqueen al extraer datos de Redfin?
Empieza con encabezados de navegador realistas y añade un retraso de entre 2 y 5 segundos entre las solicitudes. Aleatoriza los tiempos para evitar patrones predecibles. Alterna las cadenas de User-Agent y, para la recopilación a gran escala, utiliza proxies residenciales. Implementa un retroceso exponencial cuando recibas respuestas 403 o 429. Mantener sesiones persistentes con cookies también reduce el riesgo de detección.
¿Cuáles son las mejores alternativas a Redfin para obtener datos inmobiliarios?
Zillow, Realtor.com y Trulia son las plataformas más comparables en cuanto a cobertura de anuncios. El MLS (Multiple Listing Service) es la fuente de datos de referencia, pero requiere acceso con licencia. Para estadísticas de mercado agregadas, la Oficina del Censo de EE. UU. y la Agencia Federal de Financiación de la Vivienda publican conjuntos de datos gratuitos. Cada fuente tiene diferente cobertura, frecuencia de actualización y restricciones de acceso.
Resumen y próximos pasos
Ahora dispones de un kit de herramientas de Python operativo para extraer datos de Redfin en tres tipos principales: anuncios de alquiler, propiedades en venta y resultados de búsqueda. El enfoque de la API oculta te proporciona JSON limpio y estructurado sin la fragilidad del análisis de HTML, y la técnica de monitorización del mapa del sitio te permite rastrear el nuevo inventario sin necesidad de rastreos completos del sitio que suponen un desperdicio de recursos.
A partir de aquí, las extensiones naturales incluyen programar tu rastreador con cron o una cola de tareas, almacenar los resultados en una base de datos como PostgreSQL para el análisis histórico y ampliar tu proceso para cubrir otras fuentes de datos inmobiliarios. Si te encuentras dedicando más tiempo a lidiar con las protecciones antibots que a escribir la lógica de análisis, una API de rastreo dedicada como la Scraper API de WebScrapingAPI puede encargarse de la rotación de proxies y la gestión de solicitudes por ti, para que puedas centrarte en los datos en sí.




