Scarnox · Blog

Решаем PopularCaptcha в Playwright и Puppeteer (Node.js)

Автоматизация браузера останавливается, как только появляется PopularCaptcha. Кликать по сетке изображений из скрипта медленно и хрупко. Получить токен из API решения и вставить его в страницу — один запрос, а остальной скрипт продолжает работать как обычно.

Это руководство охватывает Playwright и Puppeteer на Node.js. Поток в обоих одинаков, а примеры используют решения без прокси, которые Scarnox выполняет в собственной сети. PopularCaptcha — тип, который Scarnox решает сегодня. Другие типы капчи скоро появятся, поэтому код ниже только для PopularCaptcha.

Поток

  1. Прочитать sitekey со страницы.
  2. Запросить токен у Scarnox одним блокирующим POST-запросом.
  3. Поместить токен в поле ответа или передать его callback сайта, затем отправить форму.

Настройка ключа

Создайте аккаунт и начните с бесплатного пробного баланса, карта не нужна. Храните ключ в переменной окружения, а не в тестовом коде:

export SCARNOX_KEY="scarnox_YOURAPIKEY"

Node 18 и новее включают fetch, поэтому для вызова API не нужны дополнительные пакеты.

Playwright

import { chromium } from "playwright";

const API_KEY = process.env.SCARNOX_KEY;

async function solve(sitekey, url) {
  const r = await fetch("https://api.scarnox.com/api/tasks/create", {
    method: "POST",
    headers: { Authorization: `Bearer ${API_KEY}`, "Content-Type": "application/json" },
    body: JSON.stringify({ captcha_type: "PopularCaptchaTaskProxyless", site_key: sitekey, site_url: url }),
  });
  const data = await r.json();
  if (data.errorId !== 0) throw new Error(`${data.errorCode}: ${data.errorDescription}`);
  return data.solution.token;
}

const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto("https://example.com/signup");

const sitekey = await page.getAttribute("[data-sitekey]", "data-sitekey");
const token = await solve(sitekey, page.url());

// Вставляем токен в оба поля ответа, которые может читать сайт.
await page.evaluate((t) => {
  for (const name of ["h-captcha-response", "g-recaptcha-response"]) {
    document.querySelectorAll(`[name="${name}"]`).forEach((el) => { el.value = t; });
  }
}, token);

await page.fill("#email", "you@example.com");
await page.click("button[type=submit]");

Обратите внимание, что site_url берется из page.url(). Это страница, на которой находится виджет, а решателю нужно именно она. Решение происходит после загрузки страницы, поэтому sitekey уже есть в DOM.

Puppeteer

Puppeteer отличается только API выбора элементов. Переиспользуйте функцию solve выше и замените вызовы страницы:

const sitekey = await page.$eval("[data-sitekey]", (el) => el.dataset.sitekey);
const token = await solve(sitekey, page.url());

await page.evaluate((t) => {
  document.querySelectorAll('[name="h-captcha-response"],[name="g-recaptcha-response"]')
    .forEach((el) => { el.value = t; });
}, token);

Когда сайт использует callback

Некоторые сайты не читают скрытое поле. Вместо этого они ждут JavaScript callback виджета. Найдите функцию, указанную в атрибуте data-callback виджета, и вызовите ее с токеном:

await page.evaluate((t) => {
  const name = document.querySelector("[data-sitekey]")?.dataset.callback;
  if (name && typeof window[name] === "function") window[name](t);
}, token);

Если сайт использует оба способа, заполните поле и вызовите callback. Делать оба безвредно.

Невидимые виджеты

У невидимого виджета нет чекбокса. Сайт запускает его из собственного кода, обычно когда посетитель нажимает отправку. Отправьте тот же запрос с необязательным полем is_invisible, равным true:

body: JSON.stringify({
  captcha_type: "PopularCaptchaTaskProxyless",
  site_key: sitekey,
  site_url: url,
  is_invisible: true,
}),

Руководство по невидимой капче объясняет, как распознать такие виджеты и как вернуть токен на сайт.

Советы по тайминговым ограничениям

Тестирование собственного потока

Запускайте пример на форме, которой вы владеете, прежде чем направлять его на что-то большее. Проверьте три вещи: токен принят, форма отправляется, появляется следующая страница. Когда поток работает от начала до конца, держите его зеленым в CI, делая одно настоящее решение за запуск.

Попробуйте бесплатно

Создайте аккаунт и начните с бесплатного пробного баланса, карта не нужна. Этого достаточно, чтобы подключить и проверить весь поток. Стоимость решений при большом объеме — на странице цен.

Отладка отклоненного токена

Когда сайт отклоняет токен, воспроизведите поток одним запросом и одной загрузкой страницы, прежде чем что-либо менять. Проверьте по порядку:

Сохраните HTML страницы в момент ошибки через await page.content(). Сравнение этого HTML с рабочим запуском обычно сразу показывает разницу: другой sitekey, отсутствующее поле или виджет, отрисованный в другом режиме.

Следующие шаги