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

solve recaptcha v2 in node.js - How to Solve reCAPTCHA v2 in Node.js, Including 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 — это локальный сервис распознавания капчи, поэтому ничего не тарифицируется за каждое решение.