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

solve recaptcha v2 in c# - How to Solve reCAPTCHA v2 in C#, Including 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 token

Invisible выглядит идентично, за исключением набора параметров:

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 — это локальный сервис распознавания капчи, поэтому объём ничего не стоит за решение.