Scarnox · Blog

Solver captcha w Selenium dla Pythona: działający przykład (2026)

Selenium uruchamia prawdziwą przeglądarkę, więc strona się renderuje, a skrypty działają tak, jak dla człowieka. Jedynym krokiem, którego nie potrafi wykonać, jest rozwiązanie widgetu PopularCaptcha. Ten przewodnik dodaje ten krok: odczytaj sitekey z wyrenderowanej strony, pobierz token jednym wywołaniem API, wpisz token do formularza i wyślij go.

Obejmuje widget PopularCaptcha, który Scarnox rozwiązuje dziś w trybie proxyless. Zacznij z darmowym kredytem próbnym, bez karty i przetestuj skrypt najpierw na formularzu testowym.

Co ma zrobić Selenium

Przepływ ma cztery części:

  1. Załaduj stronę i poczekaj, aż widget się wyrenderuje.
  2. Odczytaj atrybut data-sitekey z widgetu.
  3. Pobierz token z API i wstaw go do formularza.
  4. Wyślij formularz, zanim token wygaśnie.

Tylko trzeci krok dotyka captcha. Reszta to zwykła praca z Selenium.

Instalacja pakietów

pip install selenium requests

Selenium 4.6 i nowsze samo znajduje pasujący ChromeDriver, więc nie musisz pobierać sterownika ręcznie.

Pełny skrypt

import requests
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait

API_KEY = "scarnox_YOURAPIKEY"
API_URL = "https://api.scarnox.com/api/tasks/create"
PAGE_URL = "https://example.com/signup"


def solve(sitekey: str, page_url: str, invisible: bool = False) -> str:
    body = {
        "captcha_type": "PopularCaptchaTaskProxyless",
        "site_key": sitekey,
        "site_url": page_url,
    }
    if invisible:
        body["is_invisible"] = True

    r = requests.post(
        API_URL,
        headers={"Authorization": f"Bearer {API_KEY}"},
        json=body,
        timeout=185,  # blokuje się, aż token będzie gotowy
    )
    data = r.json()
    if data.get("errorId") != 0:
        raise RuntimeError(f"{data.get('errorCode')}: {data.get('errorDescription')}")
    return data["solution"]["token"]


INJECT_TOKEN_JS = """
const token = arguments[0];
let field = document.querySelector('[name="h-captcha-response"]');
if (!field) {
    field = document.createElement("textarea");
    field.name = "h-captcha-response";
    field.style.display = "none";
    document.querySelector("form").appendChild(field);
}
field.value = token;
let extra = document.querySelector('[name="g-recaptcha-response"]');
if (!extra) {
    extra = document.createElement("textarea");
    extra.name = "g-recaptcha-response";
    extra.style.display = "none";
    document.querySelector("form").appendChild(extra);
}
extra.value = token;
"""


def main() -> None:
    driver = webdriver.Chrome()
    try:
        driver.get(PAGE_URL)

        widget = WebDriverWait(driver, 15).until(
            EC.presence_of_element_located((By.CSS_SELECTOR, "[data-sitekey]"))
        )
        sitekey = widget.get_attribute("data-sitekey")
        invisible = widget.get_attribute("data-size") == "invisible"

        token = solve(sitekey, driver.current_url, invisible=invisible)

        # Najpierw wypełnij pozostałe pola, potem wstaw token tuż przed wysłaniem,
        # bo token wygasa po około dwóch minutach.
        driver.find_element(By.NAME, "email").send_keys("you@example.com")
        driver.execute_script(INJECT_TOKEN_JS, token)

        driver.find_element(By.CSS_SELECTOR, "form button[type=submit]").click()
        WebDriverWait(driver, 15).until(EC.url_changes(PAGE_URL))
        print("Submitted. Now at:", driver.current_url)
    finally:
        driver.quit()


if __name__ == "__main__":
    main()

Skrypt nie potrzebuje proxy dla rozwiązania PopularCaptcha w trybie proxyless. Pomiń pole proxy i pozwól stronie widzieć twoje zwykłe połączenie.

Kolejność operacji to część, która najczęściej się psuje. Najpierw wypełnij resztę formularza, potem rozwiąż, potem wstaw token, a na końcu kliknij. Jeśli rozwiążesz przed wpisaniem czegokolwiek w pozostałe pola, wolna strona lub wolny formularz może przesunąć wysłanie poza czas życia tokena. Utrzymuj przerwę między rozwiązaniem a kliknięciem jak najkrótszą i sprawdź stronę wyniku pod kątem błędu, zanim uznasz, że captcha przeszła.

Dlaczego token wstawiamy przez JavaScript

Większość widgetów PopularCaptcha, gdy człowiek je rozwiąże, zapisuje token w ukrytym textarea o nazwie h-captcha-response. Ponieważ Selenium nie widzi człowieka, skrypt sam zapisuje to pole. Fragment INJECT_TOKEN_JS robi dwie rzeczy:

Wypełnia też g-recaptcha-response, bo wiele stron odczytuje tę nazwę ze względu na zgodność.

Widgety niewidoczne

Niewidoczny widget nie ma pola wyboru. Działa w tle i zwykle uruchamia się przy wysyłaniu formularza. Skrypt sprawdza data-size="invisible" i wysyła is_invisible: true, gdy to zobaczy. Niektóre strony dołączają też do widgetu funkcję callback w JavaScripcie. Jeśli formularz zostaje na miejscu po wstawieniu tokena, poszukaj atrybutu data-callback i wywołaj tę funkcję z tokenem. Nasz przewodnik niewidoczna captcha omawia ten przypadek.

Użycie w testach

Selenium to też standardowe narzędzie do testów end-to-end. Jeśli twoja strona stagingowa pokazuje captcha, ten sam kod pozwala testowi ją przejść. Trzymaj środowisko testowe oddzielnie od produkcji i nie uruchamiaj go na stronach, których nie posiadasz. Konfigurację zestawów testowych opisuje captcha w testach automatycznych.

Typowe problemy

Cennik

Płacisz za każde udane rozwiązanie. Nieudane nie są naliczane. Stawki znajdziesz na stronie cennika, a zacznij z darmowym kredytem próbnym, bez karty.

Dalsze kroki