
Adélia Cruz
Neural Network Developer

detect, get_captcha_info ou solve_on_page do CapSolver Core em limites de recuperação determinísticos.Um harness de recuperação de navegador de IA é a camada de runtime que mantém uma tarefa de navegador controlada quando os estados da página mudam inesperadamente. O modelo pode decidir qual etapa de negócios vem a seguir, mas o harness deve possuir o contexto do Playwright, a política de host aprovado, checkpoints de navegação, classificação de página, recuperação de desafios suportados, limites de tentativas, rastreamentos, capturas de tela e desmontagem. O CapSolver se encaixa nessa camada como uma capacidade de recuperação determinística: o capsolver-core pode detectar desafios suportados, ler parâmetros, resolvê-los e preencher o resultado de volta na mesma página. O harness então verifica que o estado de aplicação esperado retornou antes de permitir que o agente continue. Este guia constrói o modelo de política, máquina de estado, gerenciador de contexto assíncrono, função de recuperação, gravador de artefatos, spans do OpenTelemetry, testes e controles de produção para automação de navegador autorizada confiável.
O harness não é o modelo nem o driver do navegador sozinho. É o plano de controle entre eles.
Objetivo de negócios do agente
↓
Harness de recuperação de navegador
├─ política de destino
├─ contexto do Playwright
├─ classificador de estado
├─ armazenamento de checkpoints
├─ recuperação do CapSolver
├─ orçamento de tentativas
├─ rastreamento + artefatos
└─ limpeza
↓
Ação de página aprovada ou revisão do operador
A documentação de fixtures do Playwright enfatiza fixtures de página e contexto do navegador isolados, configuração e desmontagem reutilizáveis, composabilidade e anexos de depuração automáticos. Essas propriedades se traduzem diretamente em um harness de produção.
A documentação do SDK Core do CapSolver define quatro estágios de navegador úteis: detect, get_captcha_info, solve e solve_on_page.
O modelo pode decidir abrir uma página de produto conhecida ou ler um status público. O harness decide se o host solicitado é permitido, se a página atual é esperada, se a recuperação é suportada e se o orçamento de tentativas permanece.
| Decisão | Proprietário | Motivo |
|---|---|---|
| Próxima etapa de negócios | Agente ou fluxo | Requer contexto da tarefa |
| Permissão de host e caminho | Política do harness | Deve ser determinística |
| Classificação de estado da página | Classificador do harness | Deve usar evidência confiável do DOM/rede |
| Chamada de recuperação de desafio | Harness | Requer segredos e objeto do navegador |
| Tratamento de token/cookie | Harness | Dados sensíveis de tempo de execução |
| Continuar vs revisão | Máquina de estado do harness | Impõe recuperação limitada |
| Submissão final | Humano ou serviço dedicado | Ação de alto impacto |
O guia de agentes de IA do CapSolver explica a mesma divisão de trabalho: o modelo lida com raciocínio, enquanto as camadas do CapSolver executam o trabalho de desafio suportado.
Comece com uma política estreita para hosts aprovados, caminhos, ações e orçamentos.
from dataclasses import dataclass, field
from urllib.parse import urlparse
@dataclass(frozen=True)
class TargetPolicy:
allowed_hosts: set[str]
allowed_path_prefixes: tuple[str, ...]
max_navigations: int = 20
max_recovery_attempts: int = 1
capture_screenshots: bool = True
capture_html: bool = False
allow_form_submission: bool = False
def validate_url(self, url: str) -> None:
parsed = urlparse(url)
if parsed.scheme != "https":
raise PermissionError("Apenas destinos HTTPS são permitidos")
if parsed.hostname not in self.allowed_hosts:
raise PermissionError("Host fora da política aprovada")
if not parsed.path.startswith(self.allowed_path_prefixes):
raise PermissionError("Caminho fora da política aprovada")
Use políticas específicas para o inquilino. Não mantenha uma lista de permissões global para clientes ou projetos não relacionados.
O FAQ de IA e automação do CapSolver fornece contexto de integração, enquanto o FAQ de raspagem web do CapSolver aborda fluxos de trabalho de dados públicos responsáveis.
Um harness de recuperação deve usar estados explícitos em vez de um loop "tentar novamente" ilimitado.
from enum import Enum
class BrowserState(str, Enum):
EXPECTED_PAGE = "expected_page"
SUPPORTED_CHALLENGE = "supported_challenge"
UNKNOWN_PAGE = "unknown_page"
RECOVERING = "recovering"
RECOVERED = "recovered"
REVIEW_REQUIRED = "review_required"
FAILED = "failed"
Transições permitidas podem ser representadas como dados:
ALLOWED_TRANSITIONS = {
BrowserState.EXPECTED_PAGE: {
BrowserState.EXPECTED_PAGE,
BrowserState.SUPPORTED_CHALLENGE,
BrowserState.UNKNOWN_PAGE,
},
BrowserState.SUPPORTED_CHALLENGE: {
BrowserState.RECOVERING,
BrowserState.REVIEW_REQUIRED,
},
BrowserState.RECOVERING: {
BrowserState.RECOVERED,
BrowserState.REVIEW_REQUIRED,
BrowserState.FAILED,
},
BrowserState.RECOVERED: {
BrowserState.EXPECTED_PAGE,
BrowserState.REVIEW_REQUIRED,
},
}
Valide cada transição. Isso torna loops visíveis e testáveis.
Um ponto de verificação registra metadados seguros necessários para determinar se o fluxo retomou corretamente.
from dataclasses import dataclass
from datetime import datetime, timezone
@dataclass
class BrowserCheckpoint:
url: str
title: str
expected_selector: str | None
navigation_index: int
recovery_attempts: int
observed_at: str
async def checkpoint(page, expected_selector, nav_index, attempts):
return BrowserCheckpoint(
url=page.url,
title=await page.title(),
expected_selector=expected_selector,
navigation_index=nav_index,
recovery_attempts=attempts,
observed_at=datetime.now(timezone.utc).isoformat(),
)
Não armazene estado de armazenamento, cookies, senhas, tokens ou valores completos de formulário no ponto de verificação.
Use evidência confiável do DOM, título, URL e seletores esperados. Nunca peça ao modelo para inferir o estado da página a partir de uma captura de tela apenas.
async def classify_page(page, expected_selector: str) -> BrowserState:
if await page.locator(expected_selector).count():
return BrowserState.EXPECTED_PAGE
title = (await page.title()).strip().lower()
html = (await page.content()).lower()
challenge_markers = (
"just a moment...",
"challenge-platform",
"cf-chl-",
)
if any(marker in title or marker in html for marker in challenge_markers):
return BrowserState.SUPPORTED_CHALLENGE
return BrowserState.UNKNOWN_PAGE
Use marcadores específicos do destino e fixtures controlados. Um conjunto de marcadores é uma heurística de roteamento, não uma autorização de acesso.
O FAQ de resolução de CAPTCHA do CapSolver explica fluxos de desafio suportados, e o FAQ de erros do CapSolver ajuda a classificar falhas.
O SDK Core oficial recomenda usar seu gerenciador de contexto assíncrono para que conexões HTTP sejam reutilizadas e liberadas corretamente.
import os
from capsolver_core import create_capsolver
def create_recovery_client():
return create_capsolver(
api_key=os.environ["CAPSOLVER_API_KEY"],
default_timeout=120,
polling_interval=5,
request_timeout_ms=30000,
source="ai-browser-recovery-harness",
version="1.0.0",
)
Não crie um novo cliente para cada verificação do DOM. Mantenha um cliente para o ciclo de vida do harness e feche-o durante a desmontagem.
Use detect e get_captcha_info para diagnóstico, depois solve_on_page para o fluxo completo do navegador.
from capsolver_core import SolveOnPageOptions
async def recover_supported_challenge(
cap,
page,
policy: TargetPolicy,
recovery_attempts: int,
) -> dict:
policy.validate_url(page.url)
if recovery_attempts >= policy.max_recovery_attempts:
return {
"success": False,
"state": BrowserState.REVIEW_REQUIRED,
"reason": "orçamento de recuperação esgotado",
}
detected = await cap.detect(page)
if not detected:
return {
"success": False,
"state": BrowserState.REVIEW_REQUIRED,
"reason": "nenhum desafio suportado detectado",
}
infos = await cap.get_captcha_info(page)
results = await cap.solve_on_page(
page,
options=SolveOnPageOptions(
autofill=True,
throw_on_error=False,
timeout=120,
polling_interval=5,
),
)
errors = [item.error for item in results if item.error]
filled = bool(results) and all(item.filled for item in results)
return {
"success": filled and not errors,
"state": (
BrowserState.RECOVERED
if filled and not errors
else BrowserState.REVIEW_REQUIRED
),
"detected_count": len(detected),
"info_count": len(infos),
"result_count": len(results),
"errors": errors,
}
Mantenha o objeto page original. O ponto de solve_on_page é detectar, resolver e preencher dentro da sessão de navegador existente.
Uma resposta bem-sucedida de ferramenta não prova que a página de aplicação esperada retornou.
async def verify_recovery(
page,
expected_selector: str,
timeout_ms: int = 15000,
) -> bool:
try:
await page.locator(expected_selector).wait_for(
state="visible",
timeout=timeout_ms,
)
return True
except Exception:
return False
Após a recuperação, classifique a página novamente. Se o desafio persistir ou o seletor esperado estiver ausente, pare e solicite revisão.
async def recover_and_verify(cap, page, policy, expected_selector, attempts):
result = await recover_supported_challenge(
cap=cap,
page=page,
policy=policy,
recovery_attempts=attempts,
)
if not result["success"]:
return result
if not await verify_recovery(page, expected_selector):
return {
"success": False,
"state": BrowserState.REVIEW_REQUIRED,
"reason": "página esperada não retornou após recuperação",
}
return {
"success": True,
"state": BrowserState.EXPECTED_PAGE,
"reason": "página recuperada e verificada",
}
Use um gerenciador de contexto assíncrono para garantir a limpeza.
from contextlib import asynccontextmanager
from playwright.async_api import async_playwright
@dataclass
class BrowserHarness:
policy: TargetPolicy
playwright: object
browser: object
context: object
page: object
capsolver: object
navigation_count: int = 0
recovery_attempts: int = 0
@asynccontextmanager
async def browser_recovery_harness(policy: TargetPolicy):
async with async_playwright() as playwright:
browser = await playwright.chromium.launch(headless=True)
context = await browser.new_context()
page = await context.new_page()
async with create_recovery_client() as cap:
harness = BrowserHarness(
policy=policy,
playwright=playwright,
browser=browser,
context=context,
page=page,
capsolver=cap,
)
try:
yield harness
finally:
await context.close()
await browser.close()
O modelo ou fluxo recebe métodos controlados, não acesso não restrito ao navegador.
async def safe_navigate(
harness: BrowserHarness,
url: str,
expected_selector: str,
) -> dict:
harness.policy.validate_url(url)
if harness.navigation_count >= harness.policy.max_navigations:
return {
"success": False,
"state": BrowserState.REVIEW_REQUIRED,
"reason": "orçamento de navegação esgotado",
}
harness.navigation_count += 1
await harness.page.goto(url, wait_until="domcontentloaded")
state = await classify_page(harness.page, expected_selector)
if state == BrowserState.EXPECTED_PAGE:
return {"success": True, "state": state}
if state == BrowserState.SUPPORTED_CHALLENGE:
result = await recover_and_verify(
cap=harness.capsolver,
page=harness.page,
policy=harness.policy,
expected_selector=expected_selector,
attempts=harness.recovery_attempts,
)
harness.recovery_attempts += 1
return result
return {
"success": False,
"state": BrowserState.REVIEW_REQUIRED,
"reason": "estado de página desconhecido",
}
O agente pode solicitar safe_navigate, mas o harness possui a política e o caminho de recuperação.
A orientação de observabilidade de GenAI do OpenTelemetry descreve rastreamentos para operações de modelo e ferramenta. Também observa que conteúdo completo de prompt e ferramenta pode conter dados sensíveis. Padrão para spans com apenas metadados.
from opentelemetry import trace
tracer = trace.get_tracer("capsolver.browser_harness")
async def traced_safe_navigate(harness, url, expected_selector):
with tracer.start_as_current_span("browser.safe_navigate") as span:
span.set_attribute("browser.target_host", url.split("/")[2])
span.set_attribute("browser.navigation_index", harness.navigation_count + 1)
span.set_attribute("browser.recovery_attempts", harness.recovery_attempts)
result = await safe_navigate(harness, url, expected_selector)
span.set_attribute("browser.outcome", str(result.get("state")))
span.set_attribute("browser.success", bool(result.get("success")))
return result
Não anexe tokens, cookies, chaves de API, credenciais de proxy, estado de armazenamento, conteúdo de prompt ou HTML da página completa aos spans.
Capturas de tela e HTML podem conter dados pessoais ou confidenciais. Capture-os apenas quando a política permitir, redija quando possível e armazene referências de curta duração.
from pathlib import Path
import secrets
async def capture_failure_artifacts(harness, directory: Path) -> dict:
artifact_id = secrets.token_hex(12)
screenshot = directory / f"{artifact_id}.png"
await harness.page.screenshot(
path=str(screenshot),
full_page=False,
)
return {
"artifact_id": artifact_id,
"screenshot_path": str(screenshot),
"url": harness.page.url,
"title": await harness.page.title(),
}
Use limites de retenção e controles de acesso. Evite capturar capturas de tela de página inteira quando apenas o estado de nível superior for necessário.
O blog de automação do CapSolver contém padrões de implementação relacionados, e o guia da extensão Chrome do CapSolver pode ajudar as equipes a inspecionar parâmetros de widget suportados durante o desenvolvimento.
Use contextos de navegador isolados e páginas controladas. Fixtures do Playwright fornecem configuração e limpeza reutilizáveis.
import pytest
@pytest.mark.asyncio
async def test_unknown_host_is_rejected():
policy = TargetPolicy(
allowed_hosts={"staging.example.com"},
allowed_path_prefixes=("/qa/",),
)
with pytest.raises(PermissionError):
policy.validate_url("https://other.example.net/qa/test")
@pytest.mark.asyncio
async def test_recovery_budget_is_bounded(fake_cap, fake_page):
policy = TargetPolicy(
allowed_hosts={"staging.example.com"},
allowed_path_prefixes=("/qa/",),
max_recovery_attempts=1,
)
result = await recover_supported_challenge(
cap=fake_cap,
page=fake_page,
policy=policy,
recovery_attempts=1,
)
assert result["state"] == BrowserState.REVIEW_REQUIRED
assert result["reason"] == "budget de recuperação esgotado"
Crie fixtures para sem desafio, desafio suportado, interstício desconhecido, preenchimento bem-sucedido, falha na resolução, loop de desafio pós-recuperação e seletor esperado ausente.
| Métrica | Propósito |
|---|---|
| Taxa de página esperada | Mede navegação normal bem-sucedida |
| Taxa de encontro com desafio | Mostra fricção da fonte por host aprovado |
| Taxa de sucesso na recuperação | Mede resultados de recuperação suportada |
| Taxa de loop de desafio | Detecta estado de interstício repetido |
| Taxa de página desconhecida | Encontra mudanças de layout, autenticação ou política |
| Latência de recuperação P95 | Rastreia atraso visível ao usuário |
| Taxa de revisão por operador | Mede volume de fluxo de trabalho não resolvido |
| Taxa de captura de artefato | Detecta registro excessivo de falhas |
Divida métricas por política de destino, rota, versão do navegador, tipo de desafio e versão do harness. Nunca etiquete uma falha de recuperação de desafio como falha de tarefa comercial sem preservar ambas as dimensões.
Código Bônus: Use o código WEBS no Painel CapSolver para obter um bônus adicional de 5% em cada recarga.
| Abordagem | Propriedade do navegador | Controle de recuperação | Melhor uso |
|---|---|---|---|
| Acesso direto ao navegador do agente | Runtime do agente | Dependente de prompt | Apenas protótipos de baixo risco |
| Ação específica do framework | Framework do agente | Wrapper de ferramenta | Integração rápida |
| Harness de recuperação dedicado | Camada de controle independente | Máquina de estados determinística | Confiabilidade e governança de produção |
| Recuperação exclusiva de humano | Operador | Manual | Fluxos de trabalho não suportados ou de alto risco |
Um harness dedicado requer mais engenharia, mas cria uma única camada de política e observabilidade que pode servir a múltiplos frameworks de agente.
A página de produtos CapSolver lista categorias de soluções suportadas, enquanto o blog de IA CapSolver cobre exemplos de frameworks de agente que podem chamar uma ação de harness.
Use o harness de recuperação de navegador apenas em sistemas que você possui, testa ou tem autorização explícita para automatizar. Uma solução de desafio bem-sucedida não concede permissão para acessar conteúdo privado, ignorar limites de autenticação, exceder limites de taxa ou realizar transações. Mantenha o harness escopo, leitura por padrão e auditável. Direcione a incerteza a uma pessoa em vez de expandir permissões dinamicamente.
Um harness de recuperação de navegador de IA transforma o tratamento de desafios em uma capacidade de tempo de execução controlada. Ele possui o estado do navegador, valida alvos, classifica o estado da página, invoca o Core CapSolver em uma fronteira determinística, verifica a página esperada, registra telemetria redigida e para após um número limitado de tentativas. Frameworks de agente podem usar o harness sem ganhar acesso direto a segredos ou controle de navegador sem restrições.
Comece com o CapSolver, implemente a máquina de estados contra um aplicativo de staging aprovado e adicione fixtures isolados e portas de confiabilidade antes da produção.
Não. É uma camada de tempo de execução e política independente que um framework de agente pode chamar. O harness possui estado do navegador, recuperação, pontos de verificação, telemetria e limpeza.
solve_on_page?solve_on_page combina detecção, extração de parâmetros, resolução e preenchimento DOM na mesma página do Playwright, o que o torna adequado para uma fronteira de recuperação controlada.
Prefira ações de harness estreitas como safe_navigate e read_public_page. O acesso à página bruta torna mais difícil impor políticas de alvo, navegação e recuperação.
Use uma tentativa por padrão. Desafios repetidos ou estado de página desconhecido devem ser direcionados para revisão do operador em vez de criar um loop não controlado.
Armazene metadados como host de destino, versão do harness, transições de estado, latência, erros normalizados e referências de artefato. Não armazene tokens de solução, cookies, chaves de API, credenciais de proxy, estado de armazenamento ou conteúdo de página privado.
Construa um framework de avaliação de CAPTCHA para chamadas de ferramentas de agente de IA com esquemas do CapSolver, fixtures, avaliadores de rastreamento, afirmações, conjuntos de dados de regressão e portões de CI.

Aprenda como resolver o Cloudflare Turnstile em agentes LlamaIndex com CapSolver, esquemas de FunctionTool, gerenciamento seguro de tokens, retries e recuperação do navegador.
