Использование CAPTCHA API с Selenium в C#
Вызовите solvethree через HttpClient, дождитесь готовности задачи, затем поместите solution.token в поле CAPTCHA вашего приложения. Chrome должен использовать тот же прокси и полученные параметры идентификации браузера до открытия целевой страницы.
Пример ниже использует .NET 8 и Selenium Chrome для отправки вашей собственной формы. Это прямая REST-интеграция, а не официальный SDK для C# или плагин Selenium.
На этой странице
Подготовьте проект и целевое приложение
- Используйте консольный проект .NET 8 со включёнными по умолчанию неявными директивами using. Добавьте NuGet-пакеты
Selenium.WebDriverиSelenium.Support, оба версии4.52.0. - Установите Chrome локально. Selenium Manager предоставит совместимый драйвер Chrome.
- Убедитесь, что для целевого имени хоста есть активный профиль сайта, доступный вашему рабочему пространству. Отправка имени хоста и действия не создаёт профиль; сначала выполните инструкции по настройке профиля сайта.
- Используйте прокси с разрешённым IP-адресом и без учётных данных в URL. Пример передаёт один и тот же прокси в solvethree и Chrome.
| Переменная | Что указать |
|---|---|
SOLVETHREE_API_KEY | API-ключ вашего рабочего пространства. Храните его на доверенном компьютере, где выполняется автоматизация, а не на странице. |
SOLVETHREE_PROXY | URL прокси с разрешённым IP-адресом, используемого и для решения, и для отправки через браузер. |
TARGET_URL | Полный URL страницы формы вашего приложения. Пример извлекает из него имя хоста для поля site задачи. |
Измените action в примере с login на другое действие, если его использует ваша интеграция. Пример использует значение recaptchaType по умолчанию — enterprise-v3; поля type и url в запросе задачи не нужны.
Создайте задачу и отправьте форму
Вспомогательный метод API выполняет аутентификацию с ключом рабочего пространства и отклоняет HTTP-ответы с кодами, не означающими успех, до разбора данных успешного ответа. Программа создаёт одну задачу, опрашивает её по ID, пока статус равен pending или solving, и запускает Chrome только после перехода задачи в статус 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.HTTP-тайм-аут в 30 секунд, предельный срок API в 180 секунд и ожидание Selenium в 20 секунд — настройки этого примера, а не гарантии времени работы сервиса. Настройте их в соответствии с политикой тайм-аутов вашего приложения.
Адаптируйте передачу данных к вашему приложению
- 1.
Используйте прокси вместе с полученными параметрами идентификации
ChromeOptions применяет исходный прокси и
solution.userAgent. Команды CDP включают работу с сетью и задаютsec-ch-uaизsolution.secChUaдо перехода на страницу. Соблюдайте этот порядок: не открывайте страницу до изменения параметров идентификации. - 2.
Запишите токен туда, откуда его читает приложение
Пример находит поле с именем
g-recaptcha-response, присваивает емуsolution.tokenи отправляет событие input. Замените этот механизм передачи, если ваше приложение читает токен из другого места. Заполнение поля помогает только в том случае, если исходящий запрос приложения действительно содержит его значение. - 3.
Замените селекторы отправки и успешного выполнения
Пример нажимает
button[type=submit]и ожидает появления элемента с IDsuccess. Используйте селекторы из вашего реального приложения и выберите маркер успеха, который подтверждает успешное выполнение отправленной операции, а не просто нажатие кнопки.
Готовая задача означает, что решение доступно. Проверка после отправки выполняется отдельно: целевое приложение по-прежнему само решает, принимать ли запрос.
Обрабатывайте ошибки без создания лишних задач
- Вспомогательный метод API выбрасывает исключение при получении HTTP-ответа.
Проверьте HTTP-статус и ответ с ошибкой. Это не то же самое, что переход задачи в статус
failed.Попробуйте: Исправьте указанную проблему с запросом или аутентификацией перед повторной попыткой. Не отправляйте повторно те же некорректные данные.
- Задача переходит в статус
failed. Прочитайте
errorCodeиerror;site-unreachable— одна из возможных ошибок задачи.Попробуйте: Прекратите опрос этой задачи и устраните указанную причину. Средства за неудачные решения возвращаются.
- Задача готова, но целевое приложение отклоняет отправку.
Сначала проверьте исходящий запрос приложения: содержит ли он
solution.token, а не ID задачи или старый токен? Затем проверьте прокси, user agent, клиентские подсказки и целевой URL.Попробуйте: Исправьте передачу токена или несовпадение параметров идентификации, прежде чем платить за ещё одно решение.
- После нажатия кнопки отправки истекает время ожидания Selenium.
Проверьте страницу и ответ приложения. Селектор
success— условный элемент примера, а не универсальный сигнал принятия запроса.Попробуйте: Замените его фактическим условием успешного выполнения в вашем приложении или обработайте отказ, возвращённый приложением.
Пример генерирует requestId, но не сохраняет его за вас. Если нужно восстановление после тайм-аута, сохраните его вместе с точными входными данными задачи до создания. Если время ожидания создания истекло, повторно отправьте те же данные с тем же ID, чтобы восстановить существующую задачу; не генерируйте новый ID лишь потому, что ответ был потерян. Повторное использование ID с другими входными данными вызывает конфликт. Если у вас уже есть ID задачи, вместо этого получите эту задачу.
Источники и справочник API
Запустите первую задачу.
Начните с $5 на балансе рабочего пространства.