Розв'язання PopularCaptcha у Playwright і Puppeteer (Node.js)
Автоматизація браузера зупиняється в ту мить, коли з'являється PopularCaptcha. Клікати через сітку зображень зі скрипта повільно і крихко. Отримання токена з сервісу розв'язання і вставка його на сторінку займає один запит, а решта вашого скрипта продовжує працювати як звичайно.
Цей посібник охоплює 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, відсутнє поле або віджет, відрендерений в іншому режимі.