
Aloísio Vítor
Image Processing Expert

capsolver-agent como la capa de adaptador de herramientas sobre capsolver-core, con herramientas de LangChain para marcos de agentes y métodos de navegador para sesiones de Playwright.Una integración de LangGraph Cloudflare Turnstile permite a un agente recuperarse de un paso de verificación dentro de un flujo de navegación autorizado y luego reanudar la tarea original. El gráfico no debe pedir al modelo de lenguaje que haga clic o razonar sobre el widget. En su lugar, el modelo o el controlador de navegador detecta que el flujo está bloqueado, el gráfico evalúa la política y un adaptador determinista llama a la capacidad documentada de CapSolver.
CapSolver documenta esta división del trabajo en su guía de herramientas para agentes: el modelo maneja la navegación y las decisiones, capsolver-agent expone esquemas de herramientas y un ejecutor, y capsolver-core realiza la detección, resolución y llenado de vuelta en el navegador.
Esta arquitectura da a LangGraph un papel útil. Puede hacer que la recuperación sea observable, imponer presupuestos de reintentos, enrutar acciones sensibles a un humano y asegurarse de que el navegador verifique el éxito antes de que el gráfico continúe.
Usa un entorno Python aislado. La guía oficial actual de CapSolver instala los paquetes core y agent desde GitHub:
python -m venv .venv
source .venv/bin/activate
pip install git+https://github.com/capsolver-ai/capsolver-core.git
pip install "capsolver-agent[langchain] @ git+https://github.com/capsolver-ai/capsolver-agent.git"
pip install langchain-openai langgraph playwright
playwright install chromium
Coloca CAPSOLVER_API_KEY y cualquier credencial de modelo en un almacén de secretos aprobado. No escribas valores reales en el estado del gráfico, puntos de verificación, prompts, eventos de seguimiento o archivos de código fuente.
También necesitas:
Mantén solo datos operativos no secretos en el estado del gráfico:
from typing import Literal, TypedDict
class AgentState(TypedDict, total=False):
request_id: str
purpose: str
page_id: str
current_url: str
step: str
challenge_detected: bool
challenge_attempts: int
challenge_status: Literal[
"not-needed", "pending", "resolved", "review", "denied"
]
error_code: str | None
final_assertion_passed: bool
No agregues la credencial de CapSolver, el token de solución, cookies o contenido sin procesar de la página. Almacena objetos de navegador en un registro propiedad de la aplicación, clave por page_id; los puntos de verificación del gráfico deben contener solo el identificador opaco.
La autorización debe ejecutarse antes de cualquier herramienta de desafío:
from urllib.parse import urlparse
ALLOWED_HOSTS = {"staging.example.com", "research.example.com"}
ALLOWED_PURPOSES = {"qa-validation", "public-data-research"}
def authorize_challenge(state: AgentState) -> AgentState:
host = urlparse(state["current_url"]).hostname
attempts = state.get("challenge_attempts", 0)
if host not in ALLOWED_HOSTS:
return {**state, "challenge_status": "denied", "error_code": "domain"}
if state.get("purpose") not in ALLOWED_PURPOSES:
return {**state, "challenge_status": "denied", "error_code": "purpose"}
if attempts >= 2:
return {**state, "challenge_status": "review", "error_code": "retry-limit"}
return {**state, "challenge_status": "pending"}
Este nodo es validado sintácticamente e independiente del modelo. En producción, carga la política desde configuración versionada y rechaza campos desconocidos.
class BrowserRegistry:
def __init__(self):
self._pages = {}
def register(self, page_id: str, page) -> None:
self._pages[page_id] = page
def get(self, page_id: str):
if page_id not in self._pages:
raise KeyError("browser page is not registered")
return self._pages[page_id]
async def remove(self, page_id: str) -> None:
page = self._pages.pop(page_id, None)
if page is not None:
await page.close()
El registro evita la serialización de un Page de Playwright y da a la aplicación un lugar para imponer la limpieza.
Redime tu código de bonificación de CapSolver
¡Aumenta tu presupuesto de automatización instantáneamente!
Usa el código de bonificación CAP26 al recargar tu cuenta de CapSolver para obtener un 5% adicional en cada recarga — sin límites.
Redímelo ahora en tu Panel de CapSolver
El SDK Core de CapSolver documenta detect(page) y solve_on_page(page) para el modo de navegador. El adaptador siguiente usa estos métodos y devuelve solo una decisión del gráfico:
import os
from capsolver_core import create_capsolver
async def solve_turnstile_node(
state: AgentState,
registry: BrowserRegistry,
) -> AgentState:
page = registry.get(state["page_id"])
attempts = state.get("challenge_attempts", 0) + 1
async with create_capsolver(
api_key=os.environ["CAPSOLVER_API_KEY"],
default_timeout=120,
polling_interval=5,
) as cap:
detected = await cap.detect(page)
if not detected:
return {
**state,
"challenge_attempts": attempts,
"challenge_status": "not-needed",
"error_code": None,
}
results = await cap.solve_on_page(page)
failures = [item for item in results if item.error or not item.filled]
if failures:
return {
**state,
"challenge_attempts": attempts,
"challenge_status": "review" if attempts >= 2 else "pending",
"error_code": "fill-back-failed",
}
return {
**state,
"challenge_attempts": attempts,
"challenge_status": "resolved",
"error_code": None,
}
El código ha sido verificado sintácticamente pero no ejecutado con credenciales. Una prueba en vivo requiere una página aprobada y un secreto. El gráfico nunca recibe solution.token.
Un token llenado es un resultado intermedio. Verifica el estado esperado de la aplicación:
async def verify_page_node(
state: AgentState,
registry: BrowserRegistry,
) -> AgentState:
page = registry.get(state["page_id"])
try:
await page.get_by_test_id("authorized-content").wait_for(timeout=15_000)
return {
**state,
"final_assertion_passed": True,
"step": "continue",
"error_code": None,
}
except Exception:
return {
**state,
"final_assertion_passed": False,
"challenge_status": "review",
"error_code": "page-assertion-failed",
}
Usa una afirmación propiedad de tu aplicación. Evita selectores que expongan contenido personal o sensible en los registros.
from langgraph.graph import END, StateGraph
def route_after_authorization(state: AgentState) -> str:
if state["challenge_status"] == "pending":
return "solve"
if state["challenge_status"] in {"denied", "review"}:
return "human_review"
return "verify"
def route_after_solve(state: AgentState) -> str:
if state["challenge_status"] == "resolved":
return "verify"
if state["challenge_status"] == "pending":
return "authorize"
return "human_review"
def build_graph(authorize, solve, verify, human_review):
graph = StateGraph(AgentState)
graph.add_node("authorize", authorize)
graph.add_node("solve", solve)
graph.add_node("verify", verify)
graph.add_node("human_review", human_review)
graph.set_entry_point("authorize")
graph.add_conditional_edges(
"authorize",
route_after_authorization,
{"solve": "solve", "verify": "verify", "human_review": "human_review"},
)
graph.add_conditional_edges(
"solve",
route_after_solve,
{"authorize": "authorize", "verify": "verify", "human_review": "human_review"},
)
graph.add_edge("verify", END)
graph.add_edge("human_review", END)
return graph.compile()
Las funciones inyectadas pueden cerrar sobre el registro de navegadores. La inyección de dependencias hace que las políticas y rutas de error sean testables sin un servicio en vivo.
El revisor debe recibir:
El revisor no debe recibir la credencial de CapSolver o el token de solución. Una acción que cambie el estado, como una entrega, compra, cambio de cuenta o envío de mensaje, debe requerir su propia autorización incluso después de que la verificación tenga éxito.
Las pruebas unitarias pueden reemplazar el nodo de resolución con stubs deterministas:
async def solved_stub(state: AgentState) -> AgentState:
return {
**state,
"challenge_attempts": state.get("challenge_attempts", 0) + 1,
"challenge_status": "resolved",
"error_code": None,
}
async def failed_stub(state: AgentState) -> AgentState:
return {
**state,
"challenge_attempts": state.get("challenge_attempts", 0) + 1,
"challenge_status": "review",
"error_code": "fixture-failure",
}
Prueba dominios aprobados y denegados, propósitos no admitidos, agotamiento de reintentos, páginas de navegador faltantes, un desafío resuelto con una afirmación de página fallida y la limpieza después de estados terminales.
El modo de navegador es adecuado cuando el agente ya controla una página de Playwright. El modo token puede ser más sencillo cuando tu aplicación conoce la URL y la clave pública de la página de Turnstile. CapSolver documenta la tarea AntiTurnstileTaskProxyLess con websiteURL y websiteKey requeridos, más metadata.action y metadata.cdata opcionales.
No dejes que el modelo invente estos campos. Extraelos de forma determinista de la página aprobada o de la configuración de la aplicación.
Rastrea:
No rastrees prompts que contengan credenciales, cookies de navegador, tokens sin procesar o datos de formulario no redactados. Define reglas de retención y acceso para capturas de pantalla y evidencia DOM.
Confirma que la página terminó de cargar, que el navegador usa la sesión deseada y que la versión del SDK admite el tipo de desafío. Trata un resultado de detección vacío como "not-needed" solo cuando la afirmación de página aún puede pasar.
Registra la categoría de error, compara los parámetros con la documentación actual de CapSolver y detente después del presupuesto de reintentos. No aumentes automáticamente los reintentos.
Mantén la misma página de navegador, revisa el comportamiento de la devolución de llamada o widget y verifica que la navegación de la página no haya reemplazado el contexto.
Almacena y aplica challenge_attempts. Enruta a revisión humana después del límite configurado.
Mantén separada la recuperación de CAPTCHA de la acción posterior. El gráfico debe mostrar el error de la acción en lugar de resolver nuevamente el desafío.
Una integración de LangGraph Cloudflare Turnstile es más confiable cuando se comporta como un flujo de recuperación finito: detectar, autorizar, resolver, verificar, continuar o detenerse. El gráfico proporciona enrutamiento y observabilidad; el código determinista proporciona política; CapSolver proporciona la capa de reconocimiento documentada.
Usa CapSolver solo para automatización legal y autorizada. Revisa la documentación actual de herramientas para agentes, guía del SDK Core y tutoriales relacionados de CapSolver blog antes de fijar una implementación.
P: ¿Resuelve LangGraph Cloudflare Turnstile por sí mismo?
No. LangGraph controla el estado y el enrutamiento del flujo de trabajo; el adaptador de CapSolver llama al servicio de reconocimiento y a los métodos del navegador.
P: ¿Debe devolverse el token de solución al modelo?
No. Aplica el token dentro del adaptador de navegador controlado y devuelve solo el estado, la categoría de error y el resultado de la verificación.
P: ¿Qué método de CapSolver se usa con Playwright?
El SDK Core actual documenta detect(page), get_captcha_info(page) y solve_on_page(page) para el modo de navegador.
P: ¿Cuántos reintentos debe permitir el gráfico?
Usa un pequeño presupuesto explícito basado en tu flujo y enruta a revisión en lugar de permitir un bucle sin límites.
P: ¿Puede el agente llamar al nodo de recuperación para cualquier URL?
No. Aplica una lista blanca determinista de dominios y propósitos antes de que el nodo pueda invocar a CapSolver.
P: ¿Qué demuestra que el desafío se manejó con éxito?
Una afirmación de aplicación a nivel de página demuestra la recuperación del flujo de trabajo; un estado del proveedor o un token completado por sí solo no es suficiente.
Crear una herramienta de agente solucionadora de CAPTCHA de LangChain con CapSolver, esquemas seguros, límites de reintentos y verificación para reCAPTCHA y Cloudflare Turnstile.

Construye un flujo de trabajo para resolver CAPTCHA con dispositivos de seguridad de CapSolver, identificaciones de evidencia visual, verificaciones de políticas y verificación confiable.
