Use a API de CAPTCHA com Selenium em C#
Chame o solvethree com HttpClient, aguarde a tarefa ficar pronta e coloque solution.token no campo de CAPTCHA da sua aplicação. O Chrome deve usar o mesmo proxy e a identidade de navegador retornada antes de abrir a página de destino.
O exemplo abaixo usa .NET 8 e Selenium Chrome para enviar um formulário sob seu controle. É uma integração REST direta, não um SDK oficial de C# nem um plugin do Selenium.
Nesta página
Prepare o projeto e o destino
- Use um projeto de console .NET 8 com os usings implícitos padrão habilitados. Adicione os pacotes NuGet
Selenium.WebDrivereSelenium.Support, ambos na versão4.52.0. - Instale o Chrome localmente. O Selenium Manager fornece um driver compatível com o Chrome.
- Confirme que o hostname de destino tem um perfil de site ativo disponível para seu workspace. Enviar um hostname e uma ação não cria um perfil; siga primeiro as instruções de configuração do perfil de site.
- Use um proxy com IP autorizado e sem credenciais na URL. O exemplo passa esse mesmo proxy ao solvethree e ao Chrome.
| Variável | O que fornecer |
|---|---|
SOLVETHREE_API_KEY | A chave de API do seu workspace. Mantenha-a na máquina confiável que executa a automação, não na página. |
SOLVETHREE_PROXY | A URL do proxy com IP autorizado usada tanto na resolução quanto no envio pelo navegador. |
TARGET_URL | A URL completa da página do formulário da sua aplicação. O exemplo extrai o hostname dela para o campo site da tarefa. |
Altere a action do exemplo de login se sua integração usar outra ação. Ele usa o recaptchaType padrão, enterprise-v3; a requisição da tarefa não precisa de um campo type ou url.
Crie a tarefa e envie o formulário
O helper da API autentica com a chave do seu workspace e rejeita respostas HTTP sem sucesso antes de analisar um payload de sucesso. O programa cria uma tarefa, consulta seu ID enquanto o status é pending ou solving e inicia o Chrome somente depois que a tarefa está 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.O tempo limite HTTP de 30 segundos, o prazo da API de 180 segundos e a espera do Selenium de 20 segundos são configurações deste exemplo, não garantias de tempo do serviço. Ajuste-os à política de tempo limite da sua aplicação.
Adapte a passagem do token à sua aplicação
- 1.
Mantenha o proxy e a identidade retornada juntos
ChromeOptions aplica o proxy original e
solution.userAgent. Os comandos CDP habilitam a rede e definemsec-ch-uaa partir desolution.secChUaantes da navegação. Mantenha essa ordem; não abra a página primeiro para alterar a identidade depois. - 2.
Grave o token onde a aplicação o lê
O exemplo localiza um campo chamado
g-recaptcha-response, atribuisolution.tokene dispara um evento de entrada. Substitua essa passagem se sua aplicação ler o token de outro lugar. Preencher um campo só ajuda se a requisição de saída da aplicação realmente incluir seu valor. - 3.
Substitua os seletores de envio e sucesso
O exemplo clica em
button[type=submit]e aguarda um elemento com o IDsuccess. Use seletores da sua aplicação real e escolha um indicador de sucesso que confirme que a operação enviada foi bem-sucedida — não apenas que o botão foi clicado.
Uma tarefa pronta significa que uma solução está disponível. A verificação após o envio é separada: o destino ainda decide se aceita a requisição da aplicação.
Trate falhas sem criar tarefas desnecessárias
- O helper da API lança uma exceção ao receber uma resposta HTTP.
Inspecione o status HTTP e a resposta de erro. Isso é diferente de uma tarefa chegar a
failed.Experimente: Corrija o problema de requisição ou autenticação informado antes de tentar novamente. Não continue reenviando os mesmos dados inválidos.
- A tarefa chega ao status
failed. Leia
errorCodeeerror;site-unreachableé um dos possíveis erros de tarefa.Experimente: Pare de consultar essa tarefa e resolva a causa informada. Resoluções com falha são reembolsadas.
- A tarefa está pronta, mas o destino rejeita o envio.
Inspecione primeiro a requisição de saída da aplicação: ela contém
solution.token, e não o ID da tarefa ou um token antigo? Depois, verifique o proxy, o user agent, os client hints e a URL de destino.Experimente: Corrija a passagem do token ou a incompatibilidade de identidade antes de pagar por outra resolução.
- O Selenium excede o tempo limite após clicar em enviar.
Inspecione a página e a resposta da aplicação. O seletor
successé um recurso do exemplo, não um sinal universal de aceitação.Experimente: Substitua-o pela condição real de sucesso da sua aplicação ou trate a rejeição retornada pela aplicação.
O exemplo gera um requestId, mas não o persiste para você. Salve-o com os dados exatos de entrada da tarefa antes da criação se precisar de recuperação após um tempo limite. Se a criação exceder o tempo limite, reenvie os mesmos dados com esse mesmo ID para recuperar a tarefa existente; não gere um novo ID só porque a resposta foi perdida. Reutilizar um ID com dados diferentes gera um conflito. Se você já tem o ID da tarefa, consulte essa tarefa.
Fontes e referência da API
Execute sua primeira tarefa.
Comece com $5 em créditos no espaço de trabalho.