Решаем PopularCaptcha в Playwright и Puppeteer (Node.js)
Автоматизация браузера останавливается, как только появляется PopularCaptcha. Кликать по сетке изображений из скрипта медленно и хрупко. Получить токен из API решения и вставить его в страницу — один запрос, а остальной скрипт продолжает работать как обычно.
Это руководство охватывает Playwright и Puppeteer на Node.js. Поток в обоих одинаков, а примеры используют решения без прокси, которые Scarnox выполняет в собственной сети. PopularCaptcha — тип, который Scarnox решает сегодня. Другие типы капчи скоро появятся, поэтому код ниже только для PopularCaptcha.
Поток
- Прочитать sitekey со страницы.
- Запросить токен у Scarnox одним блокирующим POST-запросом.
- Поместить токен в поле ответа или передать его 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,
}),
Руководство по невидимой капче объясняет, как распознать такие виджеты и как вернуть токен на сайт.
Советы по тайминговым ограничениям
- Запрашивайте токен непосредственно перед отправкой. Токены истекают примерно через две минуты.
- Задайте запросу на решение длинный таймаут, около 185 секунд. Он блокируется, пока токен не будет готов.
- Неудачные решения бесплатны, поэтому повтор стоит только времени. Повторяйте временные сбои с паузами, как описано в обработке ошибок и паузах.
- Запускаете много браузеров одновременно? Ограничьте число параллельных решений, чтобы одна медленная партия не задерживала весь запуск.
- Закрывайте браузеры в блоке
finally. Упавший тест, который оставляет Chromium запущенным, замедлит все последующие решения на той же машине.
Тестирование собственного потока
Запускайте пример на форме, которой вы владеете, прежде чем направлять его на что-то большее. Проверьте три вещи: токен принят, форма отправляется, появляется следующая страница. Когда поток работает от начала до конца, держите его зеленым в CI, делая одно настоящее решение за запуск.
Попробуйте бесплатно
Создайте аккаунт и начните с бесплатного пробного баланса, карта не нужна. Этого достаточно, чтобы подключить и проверить весь поток. Стоимость решений при большом объеме — на странице цен.
Отладка отклоненного токена
Когда сайт отклоняет токен, воспроизведите поток одним запросом и одной загрузкой страницы, прежде чем что-либо менять. Проверьте по порядку:
- sitekey, который вы отправили, совпадает с виджетом на загруженной странице;
site_url— это страница, на которой находится виджет, а не цель редиректа;- токен попал в поле, которое читает страница, или callback был вызван;
- отправка произошла в пределах примерно двух минут после решения.
Сохраните HTML страницы в момент ошибки через await page.content(). Сравнение этого HTML с рабочим запуском обычно сразу показывает разницу: другой sitekey, отсутствующее поле или виджет, отрисованный в другом режиме.