Scarnox · Blog

Розв'язання PopularCaptcha у Playwright і Puppeteer (Node.js)

Автоматизація браузера зупиняється в ту мить, коли з'являється PopularCaptcha. Клікати через сітку зображень зі скрипта повільно і крихко. Отримання токена з сервісу розв'язання і вставка його на сторінку займає один запит, а решта вашого скрипта продовжує працювати як звичайно.

Цей посібник охоплює 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, відсутнє поле або віджет, відрендерений в іншому режимі.

Що далі