Portais imobiliários bloqueiam scraping quase sempre da mesma forma: depois de algumas dezenas de requisições do mesmo IP, a página normal dá lugar a um desafio CAPTCHA — reCAPTCHA v3 nos grandes portais, Cloudflare Challenge nos agregadores de MLS, Turnstile em sites de leilão. A rota mais estável não é disfarçar o crawler, e sim resolver o desafio no momento em que ele aparece e seguir o fluxo normal da página. Este guia mostra os tipos de CAPTCHA mais comuns por categoria de site imobiliário, como montar um coletor em Python com a API da CaptchaAI, e quais campos priorizar numa análise de mercado — preço por m², dias no mercado, histórico de variação de preço.
CAPTCHAs mais comuns em portais e agregadores imobiliários
Cada categoria de site usa uma defesa diferente, então um coletor de dados imobiliários precisa reconhecer o tipo de desafio antes de decidir como resolvê-lo — é exatamente isso que o parâmetro method da API da CaptchaAI faz.
| Tipo de plataforma | Proteção | Tipo de CAPTCHA |
|---|---|---|
| Agregadores de MLS | Cloudflare Challenge | Desafio completo + proxy |
| Portais no estilo Zillow | reCAPTCHA v3 | Invisível, comportamental |
| Diretórios de corretores | reCAPTCHA v2 | Caixa de seleção ou invisível |
| Registros de imposto sobre a propriedade | CAPTCHA de imagem | Reconhecimento de texto |
| Sites de leilão | Cloudflare Turnstile | Desafio de widget |
| Listagens comerciais | reCAPTCHA v2 Enterprise | Verificação reforçada |
Repare que MLS e leilões usam as duas variantes de proteção da Cloudflare — Challenge e Turnstile —, então o coletor precisa tratar as duas, não só uma delas. É por isso que o código abaixo verifica reCAPTCHA e Turnstile na mesma função de busca, em vez de assumir um único tipo fixo.
Exemplo: monitorando preços de imóveis em uma região sem travar no CAPTCHA
Uma equipe de análise de mercado que acompanha o preço médio do m² em bairros de São Paulo normalmente roda o coletor todas as manhãs contra três ou quatro agregadores diferentes, em paralelo, para fechar o snapshot do dia antes das 9h. Cada agregador dispara um tipo de desafio diferente — Turnstile em um, reCAPTCHA v3 em outro — e é aí que a coleta manual trava: o script para, alguém precisa resolver o CAPTCHA na mão, e o snapshot do dia sai incompleto.
Com a API da CaptchaAI, o mesmo fluxo continua rodando sem intervenção: o parâmetro method já identifica o tipo de desafio, resolve e devolve o token para o fetch() continuar. Times que monitoram poucos portais fecham a conta com o plano BASIC (US$ 15/mês, 5 threads); quando o volume cresce para monitoramento diário de vários agregadores em paralelo, o STANDARD (US$ 30/mês, 15 threads) costuma ser o ponto de partida mais realista — o plano não cobra por CAPTCHA resolvido, só limita quantas coletas rodam ao mesmo tempo.
Como montar um coletor de dados imobiliários em Python com a API da CaptchaAI
O coletor abaixo resolve automaticamente reCAPTCHA e Cloudflare Turnstile conforme eles aparecem: detecta o sitekey na página, decide se é v2 ou v3 pela presença do script recaptcha/api.js?render=, resolve via in.php/res.php e reenvia o token no campo correto (g-recaptcha-response ou cf-turnstile-response) antes de seguir para a próxima página.
import requests
import time
import re
import json
import csv
import os
from datetime import datetime
API_KEY = os.environ["CAPTCHAAI_API_KEY"]
def solve_captcha(params):
params["key"] = API_KEY
resp = requests.get("https://ocr.captchaai.com/in.php", params=params)
if not resp.text.startswith("OK|"):
raise Exception(f"Submit: {resp.text}")
task_id = resp.text.split("|")[1]
for _ in range(60):
time.sleep(5)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY, "action": "get", "id": task_id,
})
if result.text == "CAPCHA_NOT_READY":
continue
if result.text.startswith("OK|"):
return result.text.split("|", 1)[1]
raise Exception(f"Solve: {result.text}")
raise TimeoutError()
class PropertyCollector:
def __init__(self):
self.session = requests.Session()
self.session.headers["User-Agent"] = (
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 Chrome/120.0.0.0"
)
def fetch(self, url):
"""Fetch page with automatic CAPTCHA handling."""
resp = self.session.get(url)
# reCAPTCHA
match = re.search(
r'data-sitekey=["\']([A-Za-z0-9_-]+)["\']', resp.text
)
if match:
# Detect v3
is_v3 = "recaptcha/api.js?render=" in resp.text
params = {
"method": "userrecaptcha",
"googlekey": match.group(1),
"pageurl": url,
}
if is_v3:
params["version"] = "v3"
params["action"] = "search"
token = solve_captcha(params)
resp = self.session.post(url, data={
"g-recaptcha-response": token,
})
# Turnstile
if "cf-turnstile" in resp.text:
match = re.search(r'data-sitekey=["\']([^"\']+)', resp.text)
if match:
token = solve_captcha({
"method": "turnstile",
"sitekey": match.group(1),
"pageurl": url,
})
resp = self.session.post(url, data={
"cf-turnstile-response": token,
})
return resp.text
def collect_listings(self, urls):
"""Collect property listings from multiple pages."""
listings = []
for url in urls:
try:
html = self.fetch(url)
page_listings = self._parse_listings(html)
listings.extend(page_listings)
print(f" {len(page_listings)} listings from {url}")
time.sleep(3)
except Exception as e:
print(f" Error: {url} - {e}")
return listings
def _parse_listings(self, html):
"""Extract property data from HTML."""
listings = []
# Price extraction
prices = re.findall(r'\$\s*([\d,]+)', html)
# Address extraction
addresses = re.findall(
r'class="address"[^>]*>(.*?)</(?:div|span|p)', html
)
# Bed/Bath extraction
beds = re.findall(r'(\d+)\s*(?:bed|br|bedroom)', html, re.I)
baths = re.findall(r'(\d+)\s*(?:bath|ba|bathroom)', html, re.I)
# Sqft extraction
sqft = re.findall(r'([\d,]+)\s*(?:sq\s*ft|sqft)', html, re.I)
# Combine available data
count = max(len(prices), len(addresses), 1)
for i in range(min(count, 50)): # Cap at 50 per page
listing = {
"price": prices[i] if i < len(prices) else None,
"address": (
addresses[i].strip() if i < len(addresses) else None
),
"beds": beds[i] if i < len(beds) else None,
"baths": baths[i] if i < len(baths) else None,
"sqft": sqft[i] if i < len(sqft) else None,
"collected_at": datetime.utcnow().isoformat(),
}
if listing["price"] or listing["address"]:
listings.append(listing)
return listings
def export_csv(self, listings, filename):
if not listings:
print("No listings to export")
return
keys = ["price", "address", "beds", "baths", "sqft", "collected_at"]
with open(filename, "w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=keys)
writer.writeheader()
writer.writerows(listings)
print(f"Exported {len(listings)} listings to {filename}")
# Usage
collector = PropertyCollector()
search_urls = [
"https://example-realty.com/search?city=austin&type=sale&page=1",
"https://example-realty.com/search?city=austin&type=sale&page=2",
"https://example-realty.com/search?city=austin&type=sale&page=3",
]
listings = collector.collect_listings(search_urls)
collector.export_csv(listings, "austin_listings.csv")
Quais dados de imóveis vale a pena coletar
Depois que o CAPTCHA para de interromper o fluxo, o próximo ponto de atenção é decidir o que vale a pena extrair de cada página — nem todo campo tem o mesmo peso para quem vai analisar os dados depois.
| Campo | Fonte | Caso de uso |
|---|---|---|
| Preço do anúncio | Página do imóvel | Avaliação de mercado |
| Endereço | Página do imóvel | Geoanálise |
| Quartos/banheiros/m² | Detalhes do imóvel | Análise comparável |
| Dias no mercado | Metadados do anúncio | Velocidade de venda |
| Histórico de preço | Registro de alterações | Análise de tendência |
| Imposto sobre a propriedade | Registros fiscais | Análise de investimento |
| Taxa de condomínio | Detalhes do anúncio | Análise de custo |
Como organizar a coleta diária, semanal e mensal
Depois que o coletor está estável, vale desenhar a rotina em três camadas — diária para captar o que mudou, semanal para enxergar tendência, mensal para consolidar o relatório que vai para o time de investimento:
Daily Collection
→ Property listings (500-1000 per market)
→ Price changes (delta from previous day)
→ New listings vs delisted
Weekly Analysis
→ Median price trends
→ Inventory levels
→ Days-on-market averages
→ Price-per-sqft by neighborhood
Monthly Report
→ Market heat map
→ Competitive pricing analysis
→ Investment opportunity scoring
Boas práticas e limites éticos na coleta de dados imobiliários
Dados de anúncio público — preço, endereço, características do imóvel — geralmente podem ser coletados sem problema. O limite fica claro quando o alvo passa a ser dado pessoal: telefone do corretor, e-mail do proprietário, CPF em documentos anexados. Nesses casos, a LGPD (no Brasil) e o RGPD (em Portugal) tratam esses campos como dados pessoais, e coletá-los sem base legal é o tipo de risco que nenhuma automação de CAPTCHA resolve por você.
Na prática, isso significa três coisas: extrair só o que está publicamente visível no anúncio, respeitar os termos de uso de cada portal antes de rodar o coletor em produção, e manter um intervalo entre requisições (o time.sleep(3) do exemplo acima já cumpre esse papel) para não sobrecarregar o servidor do site. Rodar a coleta com essas três regras é o que diferencia monitoramento de mercado de abuso de infraestrutura alheia.
Perguntas frequentes
A coleta de dados de imóveis é legal no Brasil e em Portugal?
Dados de anúncio público (preço, endereço, características do imóvel) geralmente podem ser coletados. Evite extrair dados pessoais de corretores ou proprietários e sempre respeite os termos de uso do site — a LGPD e o RGPD tratam dado pessoal como categoria separada, mesmo quando está dentro de um anúncio público.
Como lidar com portais que têm centenas de páginas de resultados?
Incremente o parâmetro de página na URL (?page=N ou &offset=N, dependendo do portal) e rode a coleta em lotes, com um pequeno intervalo entre requisições. Isso evita que o mesmo IP dispare o CAPTCHA com mais frequência do que o necessário.
Qual plano da CaptchaAI faz sentido para monitorar vários portais todos os dias?
Depende de quantos coletores rodam em paralelo, não de quantas páginas são coletadas por mês — o plano é por thread simultânea, com solves ilimitados em cada uma. Para dois ou três portais por vez, o BASIC (US$ 15/mês, 5 threads) costuma bastar; para monitoramento diário de vários agregadores ao mesmo tempo, o STANDARD (US$ 30/mês, 15 threads) dá mais folga.
O CaptchaAI resolve o Cloudflare Turnstile usado em sites de leilão de imóveis?
Sim. Cloudflare Turnstile é um dos tipos suportados nativamente pela API, junto com Cloudflare Challenge, reCAPTCHA v2/v3 e CAPTCHA de imagem — os mesmos tipos que aparecem na tabela no início deste guia.
Guias relacionados
- Monitoramento de preços no e-commerce
- Boas práticas de configuração de proxy
- Como fazer scraping de sites protegidos por CAPTCHA
Mantenha a coleta de dados imobiliários rodando sem travar em CAPTCHA — crie sua chave de API na CaptchaAI e automatize o monitoramento de mercado.