如何在 C# 中识别 reCAPTCHA v2,包括隐形

solve recaptcha v2 in c# - How to Solve reCAPTCHA v2 in C#, Including Invisible

reCAPTCHA v2 有三种形式,人们常常以为每种都需要各自的集成。在 C# 中它们其实都是同一个方法调用。复选框是最基本的调用,隐形增加一个选项,Enterprise 增加另一个选项,二者还可以组合。以下是完整的接口,以及之后如何处理 token。

设置

# 目标为 .NET Standard 2.0,因此 Framework 4.6.1+ 与 .NET 6-9 均可使用。
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

三种变体

变体有何变化
复选框无变化。仅需 sitekey 和 URL
隐形添加 ["invisible"] = 1
Enterprise添加 ["enterprise"] = 1
隐形 Enterprise两个键一起使用

先从复选框开始,因为其他一切都以它为基础:

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

隐形除了选项集合之外看起来完全相同:

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

对于复选框小组件,它是 data-sitekey 容器 div 上的属性。对于隐形,可能没有可见的容器,这种情况下请在 grecaptcha.render 调用,或 reCAPTCHA 脚本 URL 中获取。无论哪种方式它都是公开的,且始终以 6L开头,可以安全地硬编码。

页面 URL 比人们预想的更重要。它必须是小组件实际渲染所在的页面,而不是你的表单处理程序,也不是重定向目标。不匹配会生成一个验证时无效的 token。

提交 token

token 会写入一个名为 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);

token 有效期很短,通常约两分钟,且只能使用一次。应在流程中尽可能晚地识别,而不是一开始就识别。

有些网站根本不渲染表单字段,而是直接把 token 传给 JavaScript 回调。这是一种不同的提交方式,详见我们的 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 */ }

ValidationExceptionTimeoutException 在两个命名空间中都存在 SystemCapSkip。同时导入两个命名空间时,未限定的 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"),
    });

常见问题

如何判断小组件是隐形版还是 Enterprise 版?

隐形版没有复选框,通常在提交时触发,角落里常有一个徽标。Enterprise 版加载自 enterprise.js 而不是 api.js,因此请检查 reCAPTCHA 脚本标签。如果猜错,识别会失败而不是静默返回一个坏 token,所以两种都试一下代价很低。

我可以重复使用 token 吗?

不能。token 只能使用一次,约两分钟后过期。请在提交前立即识别,而不是建立一个 token 池。

这在 .NET Framework 上能用吗?

可以。该包面向 .NET Standard 2.0,因此 Framework 4.6.1 及更新版本可与所有现代 .NET 版本一起使用。在同步代码中你可以调用 .GetAwaiter().GetResult(),不过正确地使用 await 更好。

小结

一个方法即可涵盖全部三种变体。添加 invisibleenterprise 作为选项,使用小组件渲染所在的页面,将结果放入 g-recaptcha-response,并捕获 CapSkipError 以避免命名空间冲突。

完整的 .NET 接口见 C# 验证码识别 页面,其他语言见 reCAPTCHA v2 识别 页面,你还可以在我们的 在线 v2 演示上进行实验。CapSkip 采用 本地验证码识别工具,因此无论用量多大,每次识别都不额外收费。