Rozwiązywanie PopularCaptcha w Playwright i Puppeteer (Node.js)
Automatyzacja przeglądarki staje w miejscu w chwili, gdy pojawi się PopularCaptcha. Klikanie przez siatkę obrazków ze skryptu jest wolne i kruche. Pobranie tokena z API rozwiązującego i wstawienie go do strony to jedno żądanie, a reszta skryptu działa dalej jak zwykle.
Ten przewodnik omawia Playwright i Puppeteer w Node.js. Przebieg jest taki sam w obu, a przykłady używają rozwiązań proxyless, które Scarnox uruchamia we własnej sieci. PopularCaptcha to typ, który Scarnox rozwiązuje dziś. Inne typy captcha są wkrótce, więc poniższy kod dotyczy tylko PopularCaptcha.
Przebieg
- Odczytaj sitekey ze strony.
- Poproś Scarnox o token jednym blokującym żądaniem POST.
- Wstaw token do pola odpowiedzi albo przekaż go do callbacku strony, a potem wyślij formularz.
Konfiguracja klucza
Załóż konto i zacznij z darmowym kredytem próbnym, bez karty. Trzymaj klucz w zmiennej środowiskowej, nigdy w kodzie testów:
export SCARNOX_KEY="scarnox_YOURAPIKEY"
Node 18 i nowsze zawierają fetch, więc wywołanie API nie wymaga żadnych dodatkowych pakietów.
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());
// Wstaw token do obu pól odpowiedzi, które strona może czytać.
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]");
Zwróć uwagę, że site_url pochodzi z page.url(). To strona, na której znajduje się widget, a tego potrzebuje solver. Rozwiązanie odbywa się po załadowaniu strony, więc sitekey jest już w DOM.
Puppeteer
Puppeteer różni się tylko API selektorów. Użyj ponownie funkcji solve z powyższego przykładu i zamień wywołania strony:
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);
Gdy strona używa callbacku
Niektóre strony nie czytają ukrytego pola. Zamiast tego czekają na callback JavaScriptu widgetu. Znajdź funkcję wskazaną w atrybucie data-callback widgetu i wywołaj ją z tokenem:
await page.evaluate((t) => {
const name = document.querySelector("[data-sitekey]")?.dataset.callback;
if (name && typeof window[name] === "function") window[name](t);
}, token);
Jeśli strona używa obu mechanizmów, ustaw pole i wywołaj callback. Zrobienie obu jest nieszkodliwe.
Widgety niewidoczne
Niewidoczny widget nie ma pola wyboru. Strona uruchamia go z własnego kodu, zwykle w chwili, gdy odwiedzający naciska wyślij. Wyślij to samo żądanie z opcjonalnym polem is_invisible ustawionym na true:
body: JSON.stringify({
captcha_type: "PopularCaptchaTaskProxyless",
site_key: sitekey,
site_url: url,
is_invisible: true,
}),
Przewodnik o niewidocznej captcha wyjaśnia, jak rozpoznać takie widgety i jak przekazać token z powrotem.
Wskazówki dotyczące czasu
- Pobieraj token tuż przed wysłaniem. Tokeny wygasają po około dwóch minutach.
- Ustaw długi limit czasu dla żądania rozwiązania, około 185 sekund. Blokuje się, aż token będzie gotowy.
- Nieudane rozwiązania są bezpłatne, więc ponowienie kosztuje tylko czas. Ponawiaj przejściowe błędy z backoffem, zgodnie z opisem w obsłudze błędów i backoffie.
- Uruchamiasz wiele przeglądarek naraz? Ogranicz liczbę równoległych rozwiązań, żeby jedna wolna partia nie zatrzymała reszty przebiegu.
- Zamykaj przeglądarki w bloku
finally. Test, który się wysypał i zostawił Chromium uruchomionego, spowolni każde kolejne rozwiązanie na tej maszynie.
Testowanie własnego przepływu
Uruchom przykład na formularzu, który posiadasz, zanim skierujesz go na coś większego. Sprawdź trzy rzeczy: token został zaakceptowany, formularz się wysłał i pojawiła się następna strona. Gdy przepływ działa od początku do końca, utrzymaj go zielonym w CI, z jednym prawdziwym rozwiązaniem na przebieg.
Wypróbuj za darmo
Załóż konto i zacznij z darmowym kredytem próbnym, bez karty. To wystarczy, by podłączyć i sprawdzić cały przepływ. Koszty przy dużym wolumenie znajdziesz w aktualnym cenniku.
Debugowanie odrzuconego tokena
Gdy strona odrzuca token, odtwórz przepływ jednym żądaniem i jednym załadowaniem strony, zanim zmienisz cokolwiek innego. Sprawdź po kolei:
- Sitekey, który wysłałeś, odpowiada widgetowi na stronie, którą załadowałeś.
site_urlto strona, na której znajduje się widget, a nie cel przekierowania.- Token trafił do pola, które strona czyta, albo został wywołany callback.
- Wysłanie nastąpiło w ciągu około dwóch minut od rozwiązania.
Zapisz HTML strony w momencie błędu za pomocą await page.content(). Porównanie tego HTML z działającym przebiegiem zwykle od razu pokazuje różnicę: inny sitekey, brakujące pole albo widget wyrenderowany w innym trybie.