Voltar ao blogue
Guias
Suciu DanLast updated on Apr 27, 202614 min read

Como fazer o Scrape Redfin: Guia Python para Dados de Propriedade

Como fazer o Scrape Redfin: Guia Python para Dados de Propriedade
Resumo: A Redfin disponibiliza pontos de extremidade de API ocultos que devolvem JSON estruturado para anúncios imobiliários, permitindo evitar completamente a análise de HTML, que é um processo frágil. Este guia orienta-o na criação de um scraper em Python que extrai dados de arrendamento e venda, pesquisa por localização, monitoriza novos anúncios através de mapas de site em XML e exporta resultados organizados para CSV ou JSON.

Introdução: Porquê extrair dados de imóveis da Redfin

A Redfin é uma das maiores plataformas imobiliárias dos Estados Unidos, abrangendo milhões de anúncios residenciais em praticamente todas as áreas metropolitanas. Se precisar de extrair dados da Redfin para análise de mercado, pesquisa de investimento ou para criar uma base de dados de imóveis, a arquitetura interna da plataforma funciona, na verdade, a seu favor. Ao contrário de sites que renderizam tudo no lado do servidor, o front-end da Redfin obtém dados de pontos de extremidade de API ocultos que devolvem JSON bem estruturado. Isso significa que pode extrair dados de imóveis programaticamente sem ter de lidar com seletores CSS que falham sempre que o site atualiza o seu layout.

Neste tutorial, irá construir um scraper do Redfin baseado em Python a partir do zero. Iremos abordar três alvos de scraping distintos (anúncios de arrendamento, imóveis para venda e resultados de pesquisa), mostrar-lhe como monitorizar imóveis recém-listados através dos mapas do site XML da Redfin e guiá-lo na exportação dos seus dados para CSV e JSON. Ao longo do processo, abordaremos a limitação de taxa, as proteções anti-bot e as considerações legais que deve ter em mente antes de executar qualquer projeto de web scraping imobiliário em grande escala.

Campos de dados da Redfin que pode extrair

Antes de escrever qualquer código, é útil saber o que a Redfin realmente disponibiliza. A plataforma organiza as informações sobre imóveis em várias categorias, e conhecer os campos de dados disponíveis irá ajudá-lo a planear quais os endpoints a visar e como deve ser o seu esquema de saída.

Aqui está uma referência dos principais alvos de scraping e dos campos que pode esperar:

Alvo de scraping

Campos de dados principais

Anúncios de Venda

Preço de tabela, histórico de vendas, preço/m², quartos, casas de banho, área útil, dimensão do lote, ano de construção, quotas da HOA, tipo de imóvel, número MLS, agente imobiliário

Anúncios de arrendamento

Renda mensal, caução, condições do contrato de arrendamento, quartos, casas de banho, área útil, política relativa a animais de estimação, comodidades, data de disponibilidade, gestor da propriedade

Resultados da pesquisa

Endereço do imóvel, URL da miniatura, estado do anúncio, preço, resumo de quartos/casas de banho, dias no mercado, coordenadas

Visitas abertas

Datas agendadas, horários, agente responsável pelo anúncio, URL da propriedade associada

Perfis dos agentes

Nome do agente, agência imobiliária, transações recentes, avaliações, área de atuação

Anúncios de terrenos/lotes

Área, zoneamento, preço por acre, serviços públicos disponíveis, notas sobre a topografia

Os pontos finais de arrendamento e venda devolvem esquemas JSON diferentes, o que é importante ao projetar o seu pipeline de dados. As listagens de venda incluem campos como histórico de vendas e métricas de desempenho de mercado que não aparecem nas respostas de arrendamento, enquanto os dados de arrendamento contêm campos específicos do contrato, tais como política relativa a animais de estimação e requisitos de caução.

Pré-requisitos e configuração do projeto

Vai precisar do Python 3.8 ou posterior para este projeto. Vamos utilizar duas bibliotecas principais: httpx para efetuar pedidos HTTP (lida bem com assíncrono e tem uma API simples) e parsel para analisar quaisquer respostas HTML ou XML, especialmente ao trabalhar com mapas do site.

Crie um diretório de projeto e instale as dependências:

mkdir redfin-scraper && cd redfin-scraper
python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate
pip install httpx parsel

Opcionalmente, adicione pandas se pretender uma limpeza de dados mais avançada durante a exportação:

pip install pandas

O seu requirements.txt deve ficar assim:

httpx>=0.27.0
parsel>=1.9.0
pandas>=2.0.0

É tudo o que precisa para começar. Sem bibliotecas de automação de navegador, sem Selenium, sem Playwright. Como estamos a direcionar-nos diretamente para os pontos de extremidade da API oculta da Redfin, um simples cliente HTTP é suficiente.

Compreender os pontos de extremidade da API oculta da Redfin

Quando carregas uma página de imóveis da Redfin no teu navegador, o HTML visível é, na sua maioria, uma estrutura. Os dados reais do imóvel são obtidos de forma assíncrona a partir de pontos de extremidade da API interna. Podes descobrir esses pontos de extremidade por ti próprio abrindo as DevTools do teu navegador (F12), navegando até ao separador Rede e filtrando por pedidos «XHR» ou «Fetch» enquanto carregas uma página de listagem.

O que verá é uma série de pedidos para URLs como https://www.redfin.com/stingray/api/home/details/... que devolvem dados estruturados. As respostas começam normalmente com um prefixo de comentário (algo como {}&&{) seguido de JSON válido. Este prefixo é um padrão de proteção contra scripts entre sites, pelo que terá de o remover antes da análise.

Esta abordagem API-first para o scraping do Redfin tem vantagens significativas em relação à análise tradicional de HTML:

  • Estabilidade: os nomes dos campos JSON raramente mudam, enquanto os nomes das classes CSS podem mudar a cada implementação.
  • Exaustividade: A resposta da API contém frequentemente mais dados do que aqueles que são apresentados na página visível.
  • Velocidade: faz-se um pedido por anúncio em vez de carregar uma página completa com imagens, scripts e folhas de estilo.
  • Simplicidade: Não é necessária automação do navegador. Um cliente HTTP padrão trata de tudo.

Para descobrir o endpoint certo para qualquer tipo de anúncio, carregue a página, observe as solicitações de rede e procure aquela que contém a maior parte dos dados do imóvel na sua resposta JSON. O padrão da URL incluirá identificadores como o ID do imóvel ou um endereço codificado em URL.

Extracção de páginas de imóveis para arrendamento da Redfin

Comecemos pelas listagens de arrendamento. A Redfin disponibiliza dados de arrendamento através de um caminho de API dedicado que difere do ponto final de venda. Quando visita uma página de imóveis para arrendamento, o navegador faz uma solicitação a um ponto final que devolve os detalhes completos do arrendamento como JSON.

Aqui está um exemplo completo e funcional que recupera um anúncio de arrendamento:

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))

Algumas observações sobre este código. A clean_json_response função lida com o prefixo XSS que a Redfin antepõe às respostas da API. Os cabeçalhos imitam uma sessão de navegador real, o que é importante porque a Redfin rejeitará pedidos que pareçam vir de um script simples. A estrutura da resposta aninha os campos mais úteis sob uma payload chave, embora o aninhamento exato possa variar dependendo do tipo de anúncio. Campos específicos de arrendamento, como petPolicy e amenities não aparecerão nas respostas de imóveis à venda.

Extracção de páginas de imóveis à venda do Redfin

O endpoint de venda segue um padrão semelhante, mas o esquema JSON contém campos adicionais exclusivos dos anúncios de compra. Os imóveis à venda incluem dados históricos de preços, pontuações de competitividade de mercado e registos de avaliação fiscal que os anúncios de arrendamento simplesmente não têm.

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

As principais diferenças em relação ao scraper de arrendamentos são os campos que extrai. A priceHistory matriz fornece um registo cronológico de todas as alterações de preço desde que o anúncio foi publicado, incluindo eventos de publicação, pendentes e vendas. O taxHistory campo fornece valores avaliados ao longo do tempo, o que é útil para a análise de investimento. Campos como hoaDues e lotSize só aparecem em anúncios de venda.

Ao extrair dados de imóveis à venda da Redfin, preste atenção ao propertyType campo. Este indica se está a ver uma moradia unifamiliar, um apartamento, uma moradia em banda ou uma unidade multifamiliar, e esta distinção é importante se estiver a filtrar resultados para um segmento de mercado específico.

Extrair páginas de resultados de pesquisa do Redfin

Anúncios individuais são úteis, mas a maioria dos projetos de dados imobiliários precisa de extração em massa. A funcionalidade de pesquisa do Redfin também funciona através de uma API interna, retornando resultados paginados para uma determinada localização ou conjunto de filtros.

O endpoint de pesquisa aceita parâmetros como ID da região, tipo de imóvel, faixa de preço e deslocamento de paginação. Veja como criar um scraper de pesquisa:

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}&region_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

Vai precisar do region_id para a sua área-alvo, que pode encontrar inspecionando os pedidos de rede quando efetuar uma pesquisa no site da Redfin. O region_type=6 parâmetro indica uma pesquisa ao nível da cidade. A paginação é gerida através do incremento do page , e o ciclo termina quando a API devolve um homes .

Repare no time.sleep(2) intervalo entre as solicitações. Isto não é opcional se quiser que o seu scraper dure mais do que alguns minutos. Abordaremos a limitação de taxa com mais detalhes na secção anti-bot, mas espaçar as suas solicitações é a coisa mais importante que pode fazer para extrair os resultados de pesquisa do Redfin de forma fiável.

Exportação de dados extraídos para CSV e JSON

Depois de recolher os dados dos imóveis, precisa de os colocar num formato utilizável. Tanto o CSV como o JSON têm a sua utilidade: o CSV é melhor para análise em folhas de cálculo e importação para bases de dados, enquanto o JSON preserva estruturas aninhadas, como matrizes de histórico de vendas.

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 utilização em produção, considere alguns passos de limpeza de dados antes da exportação. Padronize as cadeias de data para o formato ISO 8601 (YYYY-MM-DD). Converta as cadeias de preços em inteiros ou números de ponto flutuante para que as ferramentas a jusante não fiquem bloqueadas com símbolos monetários. Se estiver a lidar com campos aninhados como sale_history, simplifique-os em colunas separadas para CSV ou mantenha a estrutura aninhada em JSON. Utilizando pandas com json_normalize() pode tornar esta etapa de simplificação trivial para grandes conjuntos de dados.

Rastreamento de anúncios novos e atualizados através de mapas do site

A maioria dos tutoriais de scraping da Redfin limita-se a obter páginas individuais. Mas se estiver a construir um pipeline de monitorização imobiliária, precisa de uma forma de descobrir anúncios novos e atualizados recentemente de forma automática, sem ter de rastrear novamente todo o site.

A Redfin publica mapas do site em XML que resolvem este problema. No momento da redação deste artigo, os feeds relevantes incluem:

  • https://www.redfin.com/newest_listings.xml para propriedades adicionadas recentemente
  • https://www.redfin.com/sitemap_com_latest_updates.xml para anúncios modificados recentemente

Eis como analisar estes mapas do site e introduzir os URLs no seu scraper:

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"])

A estratégia aqui é simples: consultar o mapa do site de acordo com uma programação (diária ou de hora a hora, dependendo das suas necessidades), comparar as URLs e os carimbos de data/hora com a sua base de dados existente e apenas extrair as entradas novas ou atualizadas. Esta abordagem é significativamente mais eficiente do que o rastreamento por força bruta, porque deixa que seja o Redfin a indicar-lhe o que mudou, em vez de ter de adivinhar. Se estiver interessado em extrair mapas de sites de forma mais abrangente, a mesma técnica de análise de XML aplica-se a quase todos os sites que seguem o protocolo de mapa do site.

Lidar com medidas anti-bot e evitar bloqueios

O Redfin emprega várias camadas de proteção contra o acesso automatizado. Se o seu scraper do Redfin começar a devolver erros 403 ou páginas CAPTCHA, eis o que deve verificar e como resolver a situação.

Os cabeçalhos semelhantes aos de um navegador são obrigatórios. No mínimo, defina um User-Agent, Accept, Accept-Languagee Referer . Os nossos exemplos de código já incluem estes cabeçalhos. Alterne a sua string User-Agent periodicamente, uma vez que um único valor estático em milhares de pedidos é um sinal. Compreender como configurar cabeçalhos HTTP é fundamental para qualquer projeto de scraping.

O espaçamento entre pedidos é mais importante do que os proxies. Antes de investir em infraestrutura de proxy, tente abrandar o ritmo. Um atraso de 2 a 5 segundos entre pedidos irá mantê-lo abaixo da maioria dos limites de taxa. Implemente um backoff exponencial nas tentativas: se receber um 429 ou 403, espere 30 segundos, depois 60, depois 120 antes de desistir.

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))

A rotação de proxies torna-se necessária em grande escala. Se precisar de recolher milhares de anúncios, a rotação através de um conjunto de proxies residenciais faz com que as suas solicitações pareçam vir de utilizadores diferentes. Os IPs de centros de dados tendem a ser sinalizados rapidamente em sites imobiliários.

A gestão de sessões também ajuda. A Redfin rastreia cookies entre pedidos, pelo que manter uma sessão (reutilizando a mesma httpx.Client instância) pode, na verdade, reduzir a suspeita em comparação com o envio de pedidos sem estado. Certifique-se apenas de iniciar uma nova sessão periodicamente.

Para projetos de grande volume, APIs de scraping dedicadas podem lidar com anti-detecção, rotação de proxies e resolução de CAPTCHA por trás de um único endpoint, permitindo que se concentre na lógica de análise. As dicas para evitar bloqueios de IP ao fazer web scraping aplicam-se amplamente a todas as plataformas imobiliárias, não apenas à Redfin.

Considerações legais e éticas

Antes de executar um scraper da Redfin em qualquer escala significativa, é necessário compreender o panorama jurídico. O scraping de dados publicamente disponíveis em sites é geralmente permitido nos Estados Unidos, mas existem nuances importantes.

No que diz respeito à privacidade de dados, os anúncios imobiliários podem conter informações de identificação pessoal: nomes de vendedores, detalhes de contacto de agentes e, por vezes, números de telefone. Se armazenar ou processar estes dados e servir utilizadores na UE, as obrigações do RGPD aplicam-se independentemente da localização dos seus servidores. Minimize a recolha de PII apenas ao necessário para o seu caso de utilização e implemente políticas de retenção.

Por fim, considere se a extração de dados é mesmo necessária para o seu caso de utilização. A Redfin disponibiliza um Centro de Dados que fornece dados agregados do mercado imobiliário (preços médios de venda, níveis de inventário, tempo de permanência no mercado) sob a forma de ficheiros CSV para download gratuito. Se precisar de tendências ao nível do mercado em vez de anúncios individuais, os dados oficiais podem ser suficientes.

Pontos-chave

  • Utilize os pontos de extremidade da API oculta da Redfin em vez de analisar HTML. As respostas JSON são mais estáveis, mais completas e mais rápidas de processar do que o scraping de páginas renderizadas.
  • Trate os anúncios de arrendamento e venda como modelos de dados separados. As respostas da API contêm campos diferentes, pelo que a sua lógica de extração e esquemas de saída devem ter em conta ambos.
  • Monitorize os mapas do site para anúncios novos em vez de rastrear novamente todo o site. A sondagem newest_listings.xml de acordo com um calendário é significativamente mais eficiente.
  • Respeite os limites de taxa primeiro, adicione proxies em segundo lugar. Um atraso de 2 a 5 segundos entre os pedidos evita a maioria dos bloqueios. Os proxies servem para escalar, não para substituir as regras básicas de cortesia.
  • Verifique as ofertas de dados oficiais da Redfin antes de criar um scraper. O Data Center pode já ter as métricas agregadas de que necessita.

Perguntas frequentes

A Redfin tem uma API pública para aceder a dados imobiliários?

Não. A Redfin não oferece uma API pública documentada para programadores de terceiros. Os endpoints utilizados neste guia são APIs internas que o site da Redfin invoca para preencher as suas próprias páginas. Não estão documentados e podem mudar sem aviso prévio, pelo que deve criar o seu scraper com um tratamento de erros que tenha em conta alterações no esquema.

O scraping de dados publicamente disponíveis é geralmente legal nos EUA, mas existe numa zona cinzenta. Os tribunais determinaram que o acesso a dados públicos na web não viola a Lei de Fraude e Abuso Informático, mas a violação dos Termos de Serviço de um site pode criar responsabilidade por quebra de contrato. Consulte sempre um profissional jurídico para casos de uso comercial e nunca faça scraping de dados protegidos por login sem autorização.

Como posso evitar ser bloqueado ao fazer scraping do Redfin?

Comece com cabeçalhos de navegador realistas e adicione um atraso de 2 a 5 segundos entre os pedidos. Aleatorize o seu timing para evitar padrões previsíveis. Alterne as cadeias de User-Agent e, para recolha em grande escala, utilize proxies residenciais. Implemente um backoff exponencial quando receber respostas 403 ou 429. Manter sessões persistentes com cookies também reduz o risco de deteção.

Quais são as melhores alternativas ao Redfin para dados imobiliários?

O Zillow, o Realtor.com e o Trulia são as plataformas mais comparáveis em termos de cobertura de listagens. O MLS (Multiple Listing Service) é a fonte de dados de referência, mas requer acesso licenciado. Para estatísticas de mercado agregadas, o US Census Bureau e a Federal Housing Finance Agency publicam conjuntos de dados gratuitos. Cada fonte tem cobertura, frequência de atualização e restrições de acesso diferentes.

Resumo e próximos passos

Agora dispõe de um conjunto de ferramentas Python funcional para extrair dados do Redfin em três tipos principais de dados: anúncios de arrendamento, imóveis para venda e resultados de pesquisa. A abordagem da API oculta proporciona-lhe JSON limpo e estruturado sem a fragilidade da análise de HTML, e a técnica de monitorização do mapa do site permite-lhe acompanhar novos inventários sem rastreios dispendiosos de todo o site.

A partir daqui, as extensões naturais incluem agendar o seu scraper com o cron ou uma fila de tarefas, armazenar resultados numa base de dados como o PostgreSQL para análise histórica e expandir o seu pipeline para abranger outras fontes de dados imobiliários. Se se vir a gastar mais tempo a lutar contra proteções anti-bot do que a escrever lógica de análise, uma API de scraping dedicada, como a Scraper API da WebScrapingAPI, pode tratar da rotação de proxies e da gestão de pedidos por si, para que se possa concentrar nos dados em si.

Sobre o autor
Suciu Dan, Co-fundador @ WebScrapingAPI
Suciu DanCo-fundador

Suciu Dan é cofundador da WebScrapingAPI e escreve guias práticos, voltados para programadores, sobre web scraping em Python, web scraping em Ruby e infraestruturas de proxy.

Comece a construir

Pronto para expandir a sua recolha de dados?

Junte-se a mais de 2.000 empresas que utilizam a WebScrapingAPI para extrair dados da Web à escala empresarial, sem quaisquer custos de infraestrutura.