Scarnox · Blog

Solver de captcha com Selenium em Python: exemplo funcional (2026)

O Selenium roda um navegador real, então a página é renderizada e os scripts são executados como fariam para uma pessoa. A única etapa que ele não consegue fazer é resolver o widget PopularCaptcha. Este guia acrescenta essa etapa: ler o sitekey da página renderizada, obter um token com uma chamada de API, colocar o token no formulário e enviar.

Ele cobre o widget PopularCaptcha, que a Scarnox resolve hoje em modo proxyless. Comece com crédito de teste grátis, sem cartão e teste o script em um formulário de teste antes de tudo.

O que o Selenium precisa fazer

O fluxo tem quatro partes:

  1. Carregar a página e esperar o widget ser renderizado.
  2. Ler o atributo data-sitekey do widget.
  3. Obter um token da API e colocá-lo no formulário.
  4. Enviar o formulário antes que o token expire.

A terceira etapa é a única que toca no captcha. Todo o resto é trabalho normal com Selenium.

Instale os pacotes

pip install selenium requests

O Selenium 4.6 e versões posteriores encontram um ChromeDriver compatível por conta própria, então você não precisa baixar o driver manualmente.

O script completo

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,  # bloqueia até o token estar pronto
    )
    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)

        # Preencha os outros campos antes, depois injete o token logo antes do envio,
        # porque o token expira em cerca de dois minutos.
        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()

O script não precisa de proxy para uma resolução proxyless do PopularCaptcha. Deixe de fora o campo de proxy e deixe o site ver a sua conexão normal.

A ordem das operações é a parte que mais dá errado. Preencha o restante do formulário primeiro, depois resolva, depois injete, depois clique. Se você resolver antes de digitar nos outros campos, uma página ou um formulário lento pode fazer o envio passar da validade do token. Mantenha a diferença entre a resolução e o clique o mais curta possível, e verifique a página de resultado por erros antes de presumir que o captcha passou.

Por que o token é inserido com JavaScript

A maioria dos widgets PopularCaptcha grava o token em um textarea oculto chamado h-captcha-response quando uma pessoa os resolve. Como o Selenium não tem uma pessoa, o script grava o mesmo campo por conta própria. O trecho INJECT_TOKEN_JS faz duas coisas:

Ele também preenche g-recaptcha-response, porque muitos sites leem esse nome por compatibilidade.

Widgets invisíveis

Um widget invisível não tem caixa de marcação. Ele roda em segundo plano e costuma ser disparado no envio do formulário. O script verifica data-size="invisible" e envia is_invisible: true quando o encontra. Alguns sites também associam uma função de callback JavaScript ao widget. Se o formulário continuar parado depois que você injeta o token, procure um atributo data-callback e chame essa função com o token. Nosso guia sobre captcha invisível cobre esse caso.

Usando em testes

O Selenium também é a ferramenta usual para testes end-to-end. Se o seu site de homologação exibe um captcha, o mesmo código permite que um teste passe por ele. Mantenha o ambiente de teste separado da produção, e não rode testes contra sites que você não controla. A configuração para suítes de teste está em captcha em testes automatizados.

Problemas comuns

Preços

Você paga por resolução bem-sucedida. Resoluções que falham não são cobradas. Veja a página de preços para as tarifas, e comece com crédito de teste grátis, sem cartão.

Próximos passos