Как решить reCAPTCHA v2 в C#, включая Invisible

reCAPTCHA v2 бывает трёх видов, и многие полагают, что для каждого нужна своя интеграция. В C# это один и тот же вызов метода. Checkbox — это базовый вызов, Invisible добавляет одну опцию, Enterprise — другую, и обе можно комбинировать. Вот весь набор возможностей, а также что делать с токеном потом.
Настройка
# Targets .NET Standard 2.0, so Framework 4.6.1+ and .NET 6-9 all work. dotnet add package CapSkip
CapSkip решает капчи локально, поэтому десктопное приложение должно быть запущено, прежде чем любой вызов сработает. Направьте клиент на порт, указанный в его настройках:
using CapSkip;
var solver = new CapSkipClient(
apiKey: "capskip", // any string when key validation is off
host: "127.0.0.1",
port: 8080,
recaptchaTimeout: 300); // secondsТри варианта
| Вариант | Что меняется |
|---|---|
| Checkbox | Ничего. Только sitekey и URL |
| Invisible | Добавить ["invisible"] = 1 |
| Enterprise | Добавить ["enterprise"] = 1 |
| Невидимая Enterprise | Оба ключа вместе |
Сначала checkbox, поскольку всё остальное строится на нём:
var result = await solver.RecaptchaAsync(
"6Lc...YOUR_SITEKEY", // the data-sitekey attribute
"https://example.com/login"); // the page the widget sits on
Console.WriteLine(result.Code); // g-recaptcha-response tokenInvisible выглядит идентично, за исключением набора параметров:
using System.Collections.Generic;
var result = await solver.RecaptchaAsync(sitekey, pageUrl,
new Dictionary<string, object?>
{
["invisible"] = 1,
});И Enterprise, который является ортогональным флагом, а не отдельным продуктом:
var result = await solver.RecaptchaAsync(sitekey, pageUrl,
new Dictionary<string, object?>
{
["enterprise"] = 1,
["invisible"] = 1, // combine freely if the widget is both
});Поиск sitekey
Для виджетов checkbox это data-sitekey атрибут у контейнера div. Для Invisible видимого контейнера может не быть, и тогда ищите sitekey в grecaptcha.render вызов или URL скрипта reCAPTCHA. В любом случае оно публично и всегда начинается с 6L, и его можно безопасно прописать в коде.
URL страницы важнее, чем многие думают. Это должна быть та страница, на которой фактически отображается виджет, а не обработчик вашей формы и не цель редиректа. Несовпадение приводит к токену, который при проверке оказывается недействительным.
Отправка токена
Токен помещается в поле с именем g-recaptcha-response, ровно так, как его отправил бы браузер:
using System.Net.Http;
using var http = new HttpClient();
var form = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("g-recaptcha-response", result.Code),
new KeyValuePair<string, string>("username", "..."),
new KeyValuePair<string, string>("password", "..."),
});
var response = await http.PostAsync("https://example.com/login", form);Токены недолговечны — обычно около двух минут — и одноразовые. Решайте как можно позже в процессе, а не заранее.
Некоторые сайты вообще не отображают поле формы, а вместо этого передают токен прямо в JavaScript-callback. Это другой формат отправки, и он рассматривается на нашей решатель callback для reCAPTCHA v2 странице. Само решение остаётся неизменным.
Ошибки, которые стоит перехватывать
using System;
using CapSkip;
try
{
var result = await solver.RecaptchaAsync(sitekey, pageUrl, options);
}
catch (CapSkip.ValidationException) { /* missing sitekey or url */ }
catch (NetworkException) { /* CapSkip is not running */ }
catch (ApiException) { /* bad sitekey or pageurl */ }
catch (CapSkip.TimeoutException) { /* exceeded recaptchaTimeout */ }
catch (CapSkipError) { /* anything else */ }ValidationException и TimeoutException существуют в обоих System и CapSkip. Когда импортированы оба пространства имён, неуточнённый catch привязывается к System типа и молча никогда не срабатывает. Уточняйте их, как показано выше, или ловите базовый CapSkipError и изучите его.
Параллелизм и прокси
Каждый метод возвращает Task, поэтому обычная многопоточность .NET работает:
var results = await Task.WhenAll(
solver.RecaptchaAsync(sitekeyA, "https://a.example.com"),
solver.RecaptchaAsync(sitekeyB, "https://b.example.com"));AsyncCapSkip тоже экспортируется, но в .NET это лишь псевдоним для CapSkipClient. Он существует для того, чтобы код, перенесённый из Python SDK, по-прежнему компилировался, и переход на него ничего не меняет.
Если сайт чувствителен к геолокации, решайте капчу через тот же выходной адрес, с которого будете отправлять:
var result = await solver.RecaptchaAsync(sitekey, pageUrl,
new Dictionary<string, object?>
{
["proxy"] = new Proxy("HTTPS", "user:[email protected]:3128"),
});Часто задаваемые вопросы
Как узнать, является ли виджет Invisible или Enterprise?
У Invisible нет флажка, и обычно она срабатывает при отправке, часто со значком в углу. Enterprise загружается с enterprise.js а не api.js, поэтому проверьте тег скрипта reCAPTCHA. Если вы ошибётесь в предположении, решение завершится сбоем, а не вернёт незаметно неверный токен, поэтому проверить оба варианта недорого.
Можно ли повторно использовать токен?
Нет. Токены одноразовые и истекают примерно через две минуты. Решайте капчу непосредственно перед отправкой, а не создавайте пул.
Работает ли это на .NET Framework?
Да. Пакет ориентирован на .NET Standard 2.0, поэтому Framework 4.6.1 и новее работают наравне со всеми современными выпусками .NET. Из синхронного кода вы можете вызвать .GetAwaiter().GetResult(), хотя правильнее использовать await.
Сводка
Один метод покрывает все три варианта. Добавьте invisible или enterprise в качестве опций, используйте страницу, на которой отображается виджет, поместите результат в g-recaptcha-response, и перехватить CapSkipError чтобы избежать конфликта пространств имён.
Полный набор возможностей .NET — на Решатель капчи на C# страница, другие языки покрываются Решатель reCAPTCHA v2 странице, и вы можете поэкспериментировать на нашей живая демонстрация v2. CapSkip — это локальный сервис распознавания капчи, поэтому объём ничего не стоит за решение.
