Usa la API de CAPTCHA con Selenium en C#
Llama a solvethree con HttpClient, espera a que la tarea esté lista e introduce solution.token en el campo CAPTCHA de tu aplicación. Chrome debe usar el mismo proxy y la identidad de navegador devuelta antes de abrir la página de destino.
El siguiente ejemplo usa .NET 8 y Selenium Chrome para enviar un formulario propio. Es una integración REST directa, no un SDK oficial de C# ni un plugin de Selenium.
En esta página
Prepara el proyecto y el destino
- Usa un proyecto de consola de .NET 8 con los usings implícitos predeterminados habilitados. Añade los paquetes NuGet
Selenium.WebDriverySelenium.Support, ambos en la versión4.52.0. - Instala Chrome localmente. Selenium Manager proporciona un controlador de Chrome compatible.
- Asegúrate de que el nombre de host de destino tenga un perfil de sitio activo disponible para tu espacio de trabajo. Enviar un nombre de host y una acción no lo crea; sigue primero las instrucciones de configuración del perfil de sitio.
- Usa un proxy autorizado por IP sin credenciales en su URL. El ejemplo pasa ese mismo proxy a solvethree y a Chrome.
| Variable | Qué proporcionar |
|---|---|
SOLVETHREE_API_KEY | La clave de API de tu espacio de trabajo. Mantenla en el equipo de confianza que ejecuta la automatización, no en la página. |
SOLVETHREE_PROXY | La URL del proxy autorizado por IP que se usa tanto para la resolución como para el envío desde el navegador. |
TARGET_URL | La URL completa de la página del formulario de tu aplicación. El ejemplo extrae su nombre de host para el campo site de la tarea. |
Cambia el valor de action del ejemplo, login, si tu integración usa otra acción. Se utiliza el valor predeterminado de recaptchaType, enterprise-v3; la solicitud de la tarea no necesita un campo type ni url.
Crea la tarea y envía el formulario
La función auxiliar de la API se autentica con la clave de tu espacio de trabajo y rechaza las respuestas HTTP que no indican éxito antes de analizar una respuesta de éxito. El programa crea una tarea, consulta periódicamente su ID mientras el estado es pending o solving e inicia Chrome solo cuando la tarea está en ready.
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Support.UI;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json.Nodes;
var key = Environment.GetEnvironmentVariable("SOLVETHREE_API_KEY")
?? throw new Exception("Set SOLVETHREE_API_KEY");
var proxy = Environment.GetEnvironmentVariable("SOLVETHREE_PROXY")
?? throw new Exception("Set SOLVETHREE_PROXY");
using var http = new HttpClient { Timeout = TimeSpan.FromSeconds(30) };
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", key);
using var deadline = new CancellationTokenSource(TimeSpan.FromSeconds(180));
async Task<JsonObject> Api(HttpMethod method, string path, JsonObject? body = null)
{
using var request = new HttpRequestMessage(method, "https://api.solvethree.com/v1" + path);
if (body is not null)
request.Content = new StringContent(body.ToJsonString(), Encoding.UTF8, "application/json");
using var response = await http.SendAsync(request, deadline.Token);
response.EnsureSuccessStatusCode();
return JsonNode.Parse(await response.Content.ReadAsStringAsync(deadline.Token))!.AsObject();
}
var requestId = Guid.NewGuid().ToString(); // Save with these inputs for recovery.
var input = new JsonObject {
["site"] = new Uri(Environment.GetEnvironmentVariable("TARGET_URL") ?? throw new Exception("Set TARGET_URL")).Host, ["action"] = "login",
["proxy"] = proxy, ["requestId"] = requestId
};
var task = await Api(HttpMethod.Post, "/tasks?waitMs=0", input);
while (task["status"]!.GetValue<string>() is "pending" or "solving")
{
var id = Uri.EscapeDataString(task["id"]!.GetValue<string>());
task = await Api(HttpMethod.Get, "/tasks/" + id + "?waitMs=15000");
if (task["status"]!.GetValue<string>() is "pending" or "solving")
await Task.Delay(1000, deadline.Token);
}
if (task["status"]!.GetValue<string>() != "ready")
throw new Exception("Task failed: " + task["errorCode"]?.GetValue<string>()
+ ": " + task["error"]?.GetValue<string>());
var solution = task["solution"]!.AsObject();
// Use solution["token"], ["userAgent"] and ["secChUa"] with the original proxy.
Console.WriteLine("Ready task: " + task["id"]!.GetValue<string>());
var target = Environment.GetEnvironmentVariable("TARGET_URL") ?? throw new Exception("Set TARGET_URL");
if (!string.IsNullOrEmpty(new Uri(proxy).UserInfo)) throw new Exception("Use an IP-allowlisted proxy");
var options = new ChromeOptions();
options.AddArgument("--proxy-server=" + proxy);
options.AddArgument("--user-agent=" + solution["userAgent"]!.GetValue<string>());
using var browser = new ChromeDriver(options);
browser.ExecuteCdpCommand("Network.enable", new Dictionary<string, object>());
browser.ExecuteCdpCommand("Network.setExtraHTTPHeaders", new Dictionary<string, object> {
["headers"] = new Dictionary<string, object> { ["sec-ch-ua"] = solution["secChUa"]!.GetValue<string>() }
});
browser.Navigate().GoToUrl(target);
var wait = new WebDriverWait(browser, TimeSpan.FromSeconds(20));
var field = wait.Until(driver => driver.FindElement(By.Name("g-recaptcha-response")));
browser.ExecuteScript("arguments[0].value=arguments[1]; arguments[0].dispatchEvent(new Event('input',{bubbles:true}));",
field, solution["token"]!.GetValue<string>());
browser.FindElement(By.CssSelector("button[type=submit]")).Click();
wait.Until(driver => driver.FindElement(By.Id("success"))); // Your application's success marker.El tiempo de espera HTTP de 30 segundos, el plazo de 180 segundos de la API y la espera de 20 segundos de Selenium son ajustes de este ejemplo, no garantías de tiempo del servicio. Adáptalos a la política de tiempos de espera de tu aplicación.
Adapta la transferencia del token a tu aplicación
- 1.
Mantén juntos el proxy y la identidad devuelta
ChromeOptions aplica el proxy original y
solution.userAgent. Los comandos CDP habilitan la red y configuransec-ch-uaconsolution.secChUaantes de navegar. Mantén ese orden; no abras primero la página para cambiar la identidad después. - 2.
Escribe el token donde lo lee la aplicación
El ejemplo localiza un campo llamado
g-recaptcha-response, asignasolution.tokeny dispara un evento input. Sustituye este mecanismo de transferencia si tu aplicación lee el token de otro lugar. Rellenar un campo solo sirve si la solicitud saliente de la aplicación incluye realmente su valor. - 3.
Sustituye los selectores de envío y de éxito
El ejemplo hace clic en
button[type=submit]y espera un elemento con el IDsuccess. Usa selectores de tu aplicación real y elige un indicador de éxito que confirme que la operación enviada se completó correctamente, no solo que se hizo clic en el botón.
Una tarea lista significa que hay una solución disponible. La comprobación posterior al envío es independiente: el destino sigue decidiendo si acepta la solicitud de la aplicación.
Gestiona los fallos sin crear tareas innecesarias
- La función auxiliar de la API lanza una excepción ante una respuesta HTTP.
Inspecciona el estado HTTP y la respuesta de error. Esto es distinto de que una tarea alcance el estado
failed.Prueba esto: Corrige el problema de solicitud o autenticación indicado antes de reintentarlo. No sigas reenviando los mismos datos de entrada no válidos.
- La tarea pasa al estado
failed. Lee
errorCodeyerror;site-unreachablees uno de los posibles errores de tarea.Prueba esto: Deja de consultar esa tarea y soluciona la causa indicada. Las resoluciones fallidas se reembolsan.
- La tarea está lista, pero el destino rechaza el envío.
Inspecciona primero la solicitud saliente de la aplicación: ¿contiene
solution.tokenen lugar del ID de la tarea o de un token antiguo? Después, comprueba el proxy, el agente de usuario, las indicaciones de cliente y la URL de destino.Prueba esto: Corrige la transferencia del token o la discrepancia de identidad antes de pagar por otra resolución.
- Selenium agota el tiempo de espera después de hacer clic en enviar.
Inspecciona la página y la respuesta de la aplicación. El selector
successes un elemento del ejemplo, no una señal universal de aceptación.Prueba esto: Sustitúyelo por la condición de éxito real de tu aplicación o gestiona el rechazo que haya devuelto la aplicación.
El ejemplo genera un requestId, pero no lo guarda por ti. Guárdalo junto con los datos de entrada exactos de la tarea antes de crearla si necesitas recuperarte de un tiempo de espera agotado. Si la creación agota el tiempo de espera, reenvía los mismos datos con ese mismo ID para recuperar la tarea existente; no generes un ID nuevo solo porque se haya perdido la respuesta. Reutilizar un ID con datos de entrada distintos provoca un conflicto. Si ya tienes el ID de la tarea, consulta esa tarea en su lugar.
Fuentes y referencia de la API
Ejecuta tu primera tarea.
Empieza con $5 de crédito en tu espacio de trabajo.