Как решить reCAPTCHA v2 в Node.js, включая Invisible

У reCAPTCHA v2 три варианта, и все они сводятся к одному и тому же методу Node.js. Checkbox — это простой вызов, Invisible и Enterprise — это опции в третьем аргументе, и они комбинируются. Пакет также поставляется с собственными определениями TypeScript, поэтому ничего из этого не требует отдельного @types установка.
Настройка
npm install capskip
CapSkip решает на вашем собственном компьютере, поэтому сначала должно быть запущено десктопное приложение. Затем направьте клиент на порт из его настроек:
const { CapSkip } = require('capskip');
const solver = new CapSkip({
apiKey: 'capskip', // any string when key validation is off
host: '127.0.0.1',
port: 8080,
recaptchaTimeout: 300, // seconds
});В продакшене считывайте параметры подключения из окружения:
const solver = new CapSkip({
apiKey: process.env.CAPSKIP_API_KEY || 'capskip',
host: process.env.CAPSKIP_HOST || '127.0.0.1',
port: parseInt(process.env.CAPSKIP_PORT || '8080', 10),
});Три варианта
| Вариант | Возможность добавить |
|---|---|
| Checkbox | нет |
| Invisible | { invisible: 1 } |
| Enterprise | { enterprise: 1 } |
| Невидимая Enterprise | оба ключа |
// Checkbox: sitekey and page URL, nothing else.
const result = await solver.recaptcha(
'6Lc...YOUR_SITEKEY',
'https://example.com/login',
);
console.log(result.code); // g-recaptcha-response token
// Invisible.
await solver.recaptcha(sitekey, pageUrl, { invisible: 1 });
// Enterprise, and both at once.
await solver.recaptcha(sitekey, pageUrl, { enterprise: 1 });
await solver.recaptcha(sitekey, pageUrl, { enterprise: 1, invisible: 1 });Обратите внимание на стиль аргументов. Node принимает sitekey и URL позиционно, в отличие от Python SDK, который использует именованные параметры. Именно при переносе кода между ними и возникает большинство ошибок.
TypeScript
Определения типов поставляются вместе с пакетом, поэтому это работает без дополнительной установки:
import { CapSkip, SolveResult } from 'capskip';
const solver = new CapSkip({ host: '127.0.0.1', port: 8080 });
const result: SolveResult = await solver.recaptcha(sitekey, pageUrl);SolveResult несёт captchaId и code для каждого типа, userAgent для Turnstile и три поля GeeTest. Для reCAPTCHA только code имеет значение.
Как правильно указать sitekey
Это data-sitekey атрибут на контейнере виджета или первый аргумент для grecaptcha.render когда в режиме Invisible видимого контейнера нет. Он всегда начинается с 6L и является публичным.
URL должен быть той страницей, на которой отрисовывается виджет. Передача обработчика формы или редиректа после входа — обычная причина токена, который решается без ошибок, а затем не проходит проверку.
Отправка токена
const body = new URLSearchParams({
'g-recaptcha-response': result.code,
username: '...',
password: '...',
});
const response = await fetch('https://example.com/login', {
method: 'POST',
body,
});Токены одноразовые и действуют около двух минут, поэтому решайте капчу как можно позже. Если сайт передаёт токен в JavaScript-callback, а не в поле формы, распознавание остаётся тем же, но отправка отличается, что наш решатель callback для reCAPTCHA v2 охватывает эта страница.
Решение нескольких сразу
const [a, b] = await Promise.all([ solver.recaptcha(sitekeyA, 'https://a.example.com'), solver.recaptcha(sitekeyB, 'https://b.example.com'), ]); console.log(a.code, b.code);
Пакет также экспортирует AsyncCapSkip, но в Node это лишь псевдоним для CapSkip. Ввод-вывод в Node уже асинхронный, и каждый метод уже возвращает Promise, поэтому он существует лишь для того, чтобы код, перенесённый из Python SDK, продолжал работать. Переход на него ничего не даёт.
Ошибки
const {
ValidationException, NetworkException, ApiException, TimeoutException,
} = require('capskip');
try {
const result = await solver.recaptcha(sitekey, pageUrl);
} catch (err) {
if (err instanceof ValidationException) { /* bad arguments */ }
else if (err instanceof NetworkException) { /* CapSkip not running */ }
else if (err instanceof ApiException) { /* bad sitekey or url */ }
else if (err instanceof TimeoutException) { /* polling timed out */ }
else throw err;
}Все четыре наследуют общий базовый класс, поэтому перехват CapSkipError обрабатывает всё в одной ветке, если вам так удобнее.
Часто задаваемые вопросы
Нужно ли опрашивать результат?
Нет. Клиент опрашивает результат внутренне, и Promise разрешается с готовым токеном. Он начинает проверку через 250 мс и постепенно увеличивает интервал до pollingInterval, что обычно лучше написанного вручную цикла.
Работает ли это с ESM и синтаксисом import?
Да. В примерах здесь используется require для краткости, но import { CapSkip } from 'capskip' работает, и вместе с ним поставляются встроенные определения TypeScript.
Могу ли я использовать это вместе с Puppeteer или Playwright?
Да. Решите токен с помощью этого SDK, затем внедрите его на страницу с помощью page.evaluate перед отправкой. Наш Сервис распознавания капчи для Node.js странице рассматривается сторона автоматизации браузера.
Сводка
Один метод, три варианта, выбираемые с помощью invisible и enterprise. Аргументы позиционные, токен попадает в result.code, и Promise.all — это всё, что нужно для параллелизма, потому что AsyncCapSkip здесь это просто псевдоним.
Более широкий набор возможностей Node находится в Сервис распознавания капчи для Node.js странице, другие языки на Решатель reCAPTCHA v2 страница, и есть живая демонстрация v2 для тестирования. CapSkip — это локальный сервис распознавания капчи, поэтому ничего не тарифицируется за каждое решение.
