
Adélia Cruz
Neural Network Developer

AntiCloudflareTask com um proxy estático ou fixo e um agente do usuário Chrome consistente.cf_clearance, credenciais de proxy e conteúdo bruto da página em armazenamento de curta duração, não em analytics ou contexto do modelo.O monitoramento de preços de imóveis é confiável apenas quando cada observação tem um significado e origem claros. O preço de venda de uma lista não é uma venda registrada, uma avaliação automática não é uma transação e um índice de mercado não pode ser tratado como uma cotação por imóvel. A melhor pipeline começa com conjuntos de dados oficiais e feeds licenciados, normaliza a identidade do imóvel e o tipo de preço e usa páginas públicas autorizadas apenas para lacunas definidas. Se um desafio Cloudflare suportado substituir uma página de lista esperada, o CapSolver pode fornecer um passo de recuperação controlado, mas o fluxo de trabalho deve preservar seu proxy, agente do usuário Chrome, escopo de cookies e política de fonte. Este guia abrange a hierarquia de fontes de dados, o esquema de observação, as regras de comparabilidade, a detecção de desafio, AntiCloudflareTask, recuperação de sessão de curta duração, confirmação de mudança de preço, controles de qualidade e uso responsável.
Um trabalho de monitoramento de imóveis deve especificar o sinal exato que ele precisa. Exemplos incluem:
Não colapse essas perguntas em um único campo genérico price.
monitoring_job = {
"canonical_property_id": "prop_83f12",
"market": "US-CA-San-Francisco",
"source_priority": [
"official_transaction_dataset",
"licensed_listing_feed",
"partner_api",
"authorized_public_page",
],
"price_types": ["ASKING_SALE", "RECORDED_SALE"],
"alert_rules": {
"asking_change_percent": 3.0,
"status_changes": ["ACTIVE_TO_PENDING", "PENDING_TO_SOLD"],
},
}
O blog de raspagem de web do CapSolver aborda padrões de pipeline de dados relacionados, e a FAQ de raspagem de web do CapSolver fornece orientação operacional para coleta de dados públicos autorizados.
Dados oficiais e licenciados devem ser a camada principal. O House Price Index da Agência Federal de Habitação de Finanças dos EUA é uma coleção pública de índices de vendas repetidas cobrindo vários níveis geográficos. Ele é valioso para benchmarks de mercado, mas não é um feed de listagem por imóvel.
Para dados de transação registrados, use o registro de terra, registrador ou provedor licenciado apropriado. Os Price Paid Data do governo do Reino Unido é um exemplo de conjunto de dados de transação oficial. APIs de listagem múltipla licenciadas ou portais podem fornecer observações atuais de preço de venda e status sob seus próprios contratos.
| Fonte | Significado do preço | Papel recomendado | Limitação principal |
|---|---|---|---|
| Índice de preços oficiais | Tendência do mercado | Contexto de benchmark e anomalia | Não é por imóvel |
| Registro de transação pública | Venda registrada | Verificação e histórico | Atraso na publicação varia |
| Feed de listagem licenciado | Preço de venda atual e status | Fonte primária de listagem ativa | Limites de contrato e cobertura |
| API de parceiro | Campos comerciais definidos | Fonte operacional estruturada | Semântica específica do provedor |
| Página pública autorizada | Validação para comprador | Cobertura de lacuna e QA | Validação de layout e tráfego |
A coleta de navegador deve ser um recurso para uma lacuna de dados documentada, não uma substituição para um feed licenciado disponível.
A identidade do imóvel é difícil porque os endereços mudam de formato, as unidades podem ser omitidas e um prédio pode conter muitas parcelas.
from dataclasses import dataclass
@dataclass(frozen=True)
class PropertyIdentity:
canonical_property_id: str
country: str
administrative_area: str
locality: str
postal_code: str
street_number: str
street_name: str
unit: str | None
parcel_id: str | None
latitude: float | None
longitude: float | None
Correlacione os registros com cuidado. Identificadores de parcela ou título são mais fortes que endereços normalizados; identificadores exatos de unidade são mais fortes que coordenadas de nível de prédio. Direcione correspondências ambíguas para revisão.
O guia de dados web com Python do CapSolver oferece contexto de implementação para pipelines de extração estruturada.
from dataclasses import dataclass, field
from datetime import datetime, timezone
@dataclass
class PriceObservation:
canonical_property_id: str
source: str
source_record_id: str | None
source_url: str | None
price_type: str
amount: float
currency: str
area_value: float | None
area_unit: str | None
status: str | None
market: str
evidence_hash: str
parser_version: str
observed_at: str = field(
default_factory=lambda: datetime.now(timezone.utc).isoformat()
)
Use um vocabulário de tipo de preço controlado:
PRICE_TYPES = {
"ASKING_SALE",
"RECORDED_SALE",
"ASKING_RENT_MONTHLY",
"VALUATION_ESTIMATE",
"PRICE_PER_AREA",
"MARKET_INDEX",
}
Nunca compare ASKING_SALE diretamente com RECORDED_SALE ou VALUATION_ESTIMATE. Preserve moeda e unidades de área.
Um desafio pode retornar uma página intermediária em vez da página de imóvel esperada. Não interprete seletores de preço ausentes como deslistagem ou valor zero.
async def classify_property_page(page, expected_selector: str) -> str:
if await page.locator(expected_selector).count():
return "PROPERTY_PAGE"
title = (await page.title()).strip().lower()
html = (await page.content()).lower()
if "just a moment" in title:
return "CLOUDFLARE_CHALLENGE"
if "challenge-platform" in html or "cf-chl-" in html:
return "CLOUDFLARE_CHALLENGE"
if "listing no longer available" in html:
return "LISTING_UNAVAILABLE"
return "UNKNOWN_PAGE"
Mantenha fixtures específicos da fonte. Um marcador genérico é uma dica de roteamento, não prova de que cada alvo pode ou deve ser recuperado.
A página de produto Cloudflare do CapSolver descreve o serviço suportado, e o blog Cloudflare do CapSolver contém orientação adicional de implementação.
A documentação de desafio Cloudflare do CapSolver define AntiCloudflareTask.
| Campo | Obrigatório | Uso no monitoramento de imóveis |
|---|---|---|
type |
Sim | AntiCloudflareTask |
websiteURL |
Sim | Página de lista ou registro público aprovado exato |
proxy |
Sim | Proxy estático ou fixo usado para a sessão de solicitação |
userAgent |
Opcional | Mesmo agente do usuário Chrome suportado |
html |
Condicional | HTML do desafio fresco da mesma sessão fixa |
A solução pode conter cf_clearance, token e agente do usuário. Esses são valores de tempo de execução de curta duração, não dados de imóvel.
A documentação de desafio da Cloudflare explica o papel dos mecanismos de desafio. A capacidade de recuperação não muda permissões de fonte ou limites contratuais.
import os
from urllib.parse import urlparse
SOURCE_POLICY = {
"approved-listings.example": {
"purpose": "asking-price-validation",
"proxy_profile": "property_us_west",
"max_checks_per_hour": 2,
},
}
PROXY_VAULT = {
"property_us_west": os.environ["PROPERTY_PROXY_US_WEST"],
}
def approved_source(url: str) -> dict:
host = urlparse(url).hostname
policy = SOURCE_POLICY.get(host)
if not policy:
raise PermissionError("Fonte de imóvel não é aprovada")
return policy
A URL de destino deve vir de um registro de fonte registrado, não de texto livre fornecido por modelo ou usuário em um agendador de produção.
AntiCloudflareTaskimport capsolver
capsolver.api_key = os.environ["CAPSOLVER_API_KEY"]
def solve_property_page_challenge(
url: str,
chrome_user_agent: str,
fresh_html: str = "",
) -> dict:
policy = approved_source(url)
proxy = PROXY_VAULT[policy["proxy_profile"]]
task = {
"type": "AntiCloudflareTask",
"websiteURL": url,
"proxy": proxy,
"userAgent": chrome_user_agent,
}
if fresh_html:
task["html"] = fresh_html
solution = capsolver.solve(task)
cookies = solution.get("cookies") or {}
clearance = cookies.get("cf_clearance") or solution.get("token")
if not clearance:
raise RuntimeError("Solução de desafio Cloudflare incompleta")
return {
"cookies": cookies,
"user_agent": solution.get("userAgent") or chrome_user_agent,
"proxy_profile": policy["proxy_profile"],
}
Use um proxy estático ou fixo e o preserve para a solicitação inicial, criação da tarefa e recuperação da página. Não coloque credenciais de proxy em logs.
A documentação oficial do CapSolver exige um cliente de solicitação com TLS e detalhes de sessão consistentes. Mantenha essa implementação dentro de um adaptador de fonte testado.
async def recover_property_document(
source_adapter,
url: str,
challenge_html: str,
user_agent: str,
) -> str:
solution = solve_property_page_challenge(
url=url,
chrome_user_agent=user_agent,
fresh_html=challenge_html,
)
response = await source_adapter.fetch_with_session(
url=url,
proxy_profile=solution["proxy_profile"],
user_agent=solution["user_agent"],
cookies=solution["cookies"],
)
if response.status_code != 200:
raise RuntimeError("Solicitação recuperada não retornou HTTP 200")
if "challenge-platform" in response.text.lower():
raise RuntimeError("Desafio permaneceu após um tentativa de recuperação")
return response.text
fetch_with_session é um adaptador de propriedade da aplicação que usa o perfil TLS aprovado. Ele não deve expor cookies, valores de proxy ou cabeçalhos para analytics.
Páginas públicas variam. Use um adaptador por fonte aprovada com seletores explícitos e verificações semânticas.
from decimal import Decimal, InvalidOperation
class SourceAdapter:
source_name = "approved-listings"
parser_version = "2026-08-28.1"
def parse_asking_price(self, document) -> dict:
raw = document.select_one('[data-testid="asking-price"]')
if raw is None:
raise ValueError("Campo de preço de venda não encontrado")
currency = raw.get("data-currency")
amount_text = raw.get("data-amount")
try:
amount = Decimal(amount_text)
except (InvalidOperation, TypeError):
raise ValueError("Valor de preço de venda inválido")
if amount <= 0 or not currency:
raise ValueError("Observação de preço de venda incompleta")
return {
"price_type": "ASKING_SALE",
"amount": float(amount),
"currency": currency,
}
Não trate uma estimativa de marketing, ilustração de hipoteca mensal ou preço "a partir de" como preço de venda.
from decimal import Decimal
def comparable(left: PriceObservation, right: PriceObservation) -> bool:
return all([
left.canonical_property_id == right.canonical_property_id,
left.price_type == right.price_type,
left.currency == right.currency,
left.market == right.market,
])
def percentage_change(previous: float, current: float) -> float:
if previous <= 0:
raise ValueError("Preço anterior deve ser positivo")
return float(
(Decimal(str(current)) - Decimal(str(previous)))
/ Decimal(str(previous))
* 100
)
Se a área mudar, uma unidade for adicionada ou uma lista for relistada sob uma identidade de imóvel diferente, exija revisão em vez de relatar uma movimentação de preço falsa.
Uma observação única pode ser ruidosa. Use confirmação repetida ou corroboração de fonte.
def confirmed_price_change(
observations: list[PriceObservation],
threshold_percent: float,
) -> dict | None:
if len(observations) < 3:
return None
baseline, first_new, second_new = observations[-3:]
if not comparable(baseline, first_new):
return None
if not comparable(first_new, second_new):
return None
if first_new.amount != second_new.amount:
return None
change = percentage_change(baseline.amount, second_new.amount)
if abs(change) < threshold_percent:
return None
return {
"event": "CONFIRMED_PRICE_CHANGE",
"previous": baseline.amount,
"current": second_new.amount,
"currency": second_new.currency,
"change_percent": round(change, 2),
}
Para conjuntos de dados de transação, use o horário de publicação da fonte e política de revisão em vez de confirmação repetida do navegador.
| Evento | Significado | Destino |
|---|---|---|
PRICE_CHANGE_CONFIRMED |
Observação de preço comparável mudou | Alerta para analista ou cliente |
STATUS_CHANGED |
Estado ativo, pendente, vendido ou removido mudou | Fluxo de trabalho de lista |
CHALLENGE_ENCOUNTERED |
Fonte apresentou um desafio suportado | Painel de automação |
RECOVERY_FAILED |
Recuperação não retornou a página esperada | Revisão do operador |
PARSER_UNKNOWN |
Página retornada, mas semântica de preço foi ambígua | Fila de qualidade de dados |
SOURCE_STALE |
Feed oficial ou página não foi atualizado | Monitor de saúde da fonte |
Nunca converta um desafio, timeout ou erro de parser em um preço de zero ou status de deslistado.
A Perguntas frequentes sobre erros do CapSolver fornece categorias de diagnóstico, e a blog de automação do CapSolver aborda padrões de recuperação relacionados.
Código de bônus: Use o código WEBS no Painel do CapSolver para obter um bônus adicional de 5% em cada recarga.
| Controle | Implementação recomendada |
|---|---|
| Autorização de fonte | Contrato ou aprovação escrita vinculada ao propósito |
| Prioridade da fonte | Dados oficiais/parceiros antes de fallback na página |
| Escopo do alvo | Lista de permissões de host e caminho |
| Proxy | Perfil do lado do servidor estático ou estático |
| Agente do usuário | Identidade do Chrome suportada mesma através da recuperação |
| Tentativa de desafio | Uma tentativa, depois revisão |
| Semântica de preço | Tipo de preço explícito, moeda, unidade e status |
| Evidência | ID da fonte, horário, versão do parser e hash |
| Alertas | Alterações comparáveis confirmadas apenas |
| Retenção | Cookies de curta duração; observações de propriedades reguladas |
Use a página de produtos do CapSolver para revisar categorias suportadas e a Perguntas frequentes sobre resolução de CAPTCHA do CapSolver para orientação sobre fluxo de tarefas.
Monitore apenas dados aos quais você tem autorização para acessar. Siga contratos de feed de listagem, licenças de registro, termos da fonte, limites de taxa, leis de privacidade e requisitos de habitação justa. Não colete dados de conta privada, detalhes de contato do proprietário, informações de inquilino, registros de aplicação ou relatórios de avaliação restritos sem base legal válida. Mantenha a recuperação de desafios limitada a um fluxo de trabalho público ou parceiro aprovado. Capacidade técnica não concede permissão.
O monitoramento confiável de preços de imóveis depende de observações comparáveis e origem clara. Índices oficiais e conjuntos de dados de transações fornecem a base; feeds licenciados fornecem detalhes atuais de listagem; páginas autorizadas preenchem lacunas definidas. Quando um desafio Cloudflare suportado interrompe esse fallback, use o CapSolver com um proxy estático ou estático, agente de usuário do Chrome consistente, cookies de curta duração, uma tentativa de recuperação e verificação explícita da página.
Inicie um fluxo de trabalho aprovado de dados imobiliários com o CapSolver, valide-o contra uma fonte controlada e adicione regras de tipo de preço, evidência e confirmação antes de escalar alertas.
Não. É um índice de mercado construído a partir de transações repetidas e publicado em vários níveis geográficos. Use-o como referência, não como preço de lista individual.
Use a AntiCloudflareTask documentada com a URL de destino exata e um proxy estático ou estático. Um agente de usuário do Chrome suportado consistente e HTML de desafio atual também podem ser necessários.
Eles devem ser armazenados como tipos de preço diferentes. Qualquer comparação deve explicar que um é uma oferta do vendedor e o outro é uma transação concluída.
Não. Registre um erro de infraestrutura ou parser e verifique o estado da página. Um seletor ausente não é evidência de que a lista tenha sido removida.
cf_clearance deve ser retido?Mantenha-o apenas para a sessão de solicitação aprovada de curta duração. Não o armazene em análises de propriedade, contexto de modelo, registros de longo prazo ou alertas de clientes.
Diagnose os fluxos de desafio do Cloudflare com o AntiCloudflareTask, proxy estável e identidade do agente de usuário, HTML atualizado, tratamento de limpeza, validação e erros seguros.

Construa um monitoramento de estoque de comércio eletrônico confiável com sourcing baseado em API, recuperação de desafios da Cloudflare, consistência de sessão, evidência de estoque e alertas confiáveis.
