Tutorials

Extraindo parâmetros reCAPTCHA da origem da página

Toda requisição de resolução de reCAPTCHA enviada à API da CaptchaAI depende de dois dados mínimos: a sitekey certa (a chave pública do widget) e a URL exata da página testada.

Errar a versão do action, esquecer o data-s ou não marcar a flag enterprise costuma causar falha de validação do lado do Google, não da CaptchaAI — e o sintoma é sempre o mesmo: a task não resolve. Este guia reúne os quatro métodos práticos para extrair esses parâmetros do código-fonte, do script de carregamento ou da renderização em JavaScript, fechando com uma função Python completa para o seu pipeline de QA.

Use estes métodos apenas em páginas que você tem autorização para testar — ambiente próprio, staging ou contas de QA.

Os quatro métodos, em ordem de prioridade

Nem todo site expõe a sitekey do mesmo jeito. Use esta ordem como checklist — é a mesma sequência que a função completa deste guia percorre automaticamente:

  1. Atributos HTML (data-sitekey) — funciona sem navegador na maioria dos sites.
  2. Tag de script — necessário para reCAPTCHA v3 e Enterprise.
  3. Src do iframe — cobre widgets montados manualmente, sem a biblioteca oficial do Google.
  4. Renderização via grecaptcha.render() — para páginas que montam o widget de forma dinâmica.

Método 1: extrair pelos atributos HTML

Quando o widget do reCAPTCHA é renderizado no HTML estático, os atributos data-* já trazem tudo o que você precisa — nenhum navegador é necessário.

Pelo atributo data-sitekey. O caminho mais direto é buscar data-sitekey no HTML com requests e regex, conferindo também se o widget é invisível e se há callback configurado:

import re
import requests

url = "https://staging.example.com/qa-login"
html = requests.get(url).text

# Find data-sitekey
match = re.search(r'data-sitekey=["\']([A-Za-z0-9_-]+)["\']', html)
if match:
    sitekey = match.group(1)
    print(f"Sitekey: {sitekey}")

# Check if invisible
invisible_match = re.search(r'data-size=["\']invisible["\']', html)
is_invisible = bool(invisible_match)
print(f"Invisible: {is_invisible}")

# Find callback
callback_match = re.search(r'data-callback=["\'](\w+)["\']', html)
callback = callback_match.group(1) if callback_match else None
print(f"Callback: {callback}")

# Check for data-s (Google-owned sites)
data_s_match = re.search(r'data-s=["\']([^"\']+)["\']', html)
data_s = data_s_match.group(1) if data_s_match else None
print(f"data-s: {data_s}")

Via Puppeteer, quando o JavaScript monta o widget. Se a página monta o widget depois do carregamento inicial — comum em React ou Vue —, o HTML bruto não mostra nada. Use o Puppeteer para renderizar a página e ler os atributos direto do DOM:

const puppeteer = require('puppeteer');

const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://staging.example.com/qa-login', { waitUntil: 'networkidle2' });

const params = await page.evaluate(() => {
  const widget = document.querySelector('.g-recaptcha');
  if (!widget) return null;

  return {
    sitekey: widget.getAttribute('data-sitekey'),
    size: widget.getAttribute('data-size'),
    callback: widget.getAttribute('data-callback'),
    dataS: widget.getAttribute('data-s'),
    invisible: widget.getAttribute('data-size') === 'invisible',
  };
});

console.log(params);

Método 2: extrair pela tag de script

reCAPTCHA v3 e Enterprise não desenham widget visível, então os atributos data-* não existem. A sitekey e o modo Enterprise aparecem na tag <script> que carrega a biblioteca do Google.

Sitekey de v3 e Enterprise. A sitekey do v3 vem embutida no parâmetro render da URL do script:

# Find sitekey from script src
v3_match = re.search(
    r'recaptcha/(?:api|enterprise)\.js\?.*?render=([A-Za-z0-9_-]+)',
    html
)
if v3_match:
    sitekey = v3_match.group(1)
    print(f"v3 Sitekey: {sitekey}")

# Check enterprise
is_enterprise = 'enterprise.js' in html
print(f"Enterprise: {is_enterprise}")

O parâmetro action. Ele não fica em nenhum atributo HTML — é passado como argumento na chamada grecaptcha.execute(), dentro do próprio JavaScript da página:

# Search for grecaptcha.execute calls
action_match = re.search(
    r'grecaptcha\.execute\s*\([^,]+,\s*\{[^}]*action\s*:\s*["\']([^"\']+)',
    html
)
if action_match:
    action = action_match.group(1)
    print(f"Action: {action}")

Método 3: extrair pelo src do iframe

Alguns sites incorporam o reCAPTCHA sem carregar a biblioteca oficial do Google, montando o iframe manualmente. Nesse caso, a sitekey aparece no parâmetro k da própria URL do iframe:

# Find reCAPTCHA iframe
iframe_match = re.search(
    r'<iframe[^>]+src=["\']([^"\']*recaptcha/api2/anchor[^"\']*)["\']',
    html
)
if iframe_match:
    iframe_src = iframe_match.group(1)
    sitekey_match = re.search(r'k=([A-Za-z0-9_-]+)', iframe_src)
    if sitekey_match:
        sitekey = sitekey_match.group(1)
        print(f"Iframe sitekey: {sitekey}")

Método 4: extrair via renderização dinâmica em JavaScript

Sites que chamam grecaptcha.render() explicitamente passam a sitekey, o callback e o tamanho como um objeto de configuração no próprio JavaScript:

# Find grecaptcha.render calls
render_match = re.search(
    r'grecaptcha\.render\s*\([^,]*,\s*\{([^}]+)\}',
    html
)
if render_match:
    config = render_match.group(1)
    sk = re.search(r'sitekey\s*:\s*["\']([A-Za-z0-9_-]+)', config)
    cb = re.search(r'callback\s*:\s*["\']?(\w+)', config)
    sz = re.search(r'size\s*:\s*["\'](\w+)', config)
    print(f"Sitekey: {sk.group(1) if sk else 'not found'}")
    print(f"Callback: {cb.group(1) if cb else 'not found'}")
    print(f"Size: {sz.group(1) if sz else 'not found'}")

Quais parâmetros o reCAPTCHA exige em cada versão

Use esta tabela como checklist final antes de montar a requisição — ela resume o que cada versão exige.

Parâmetro v2 padrão v2 invisível v3 Enterprise
googlekey (sitekey) Obrigatório Obrigatório Obrigatório Obrigatório
pageurl Obrigatório Obrigatório Obrigatório Obrigatório
invisible - 1 - -
action - - Obrigatório Às vezes
data-s Às vezes Às vezes - -
enterprise - - - 1

Função completa de extração

Raramente dá para saber de antemão qual método vai funcionar em um site novo. A função abaixo tenta todos na mesma ordem de prioridade até encontrar uma sitekey válida, e devolve tudo pronto para a chamada à API:

import re
import requests

def extract_recaptcha_params(url):
    html = requests.get(url, timeout=15).text
    params = {"pageurl": url}

    # Sitekey from data-sitekey
    sk = re.search(r'data-sitekey=["\']([A-Za-z0-9_-]+)', html)
    if sk:
        params["sitekey"] = sk.group(1)

    # Sitekey from script render parameter (v3)
    if "sitekey" not in params:
        v3 = re.search(r'render=([A-Za-z0-9_-]{20,})', html)
        if v3:
            params["sitekey"] = v3.group(1)

    # Sitekey from iframe
    if "sitekey" not in params:
        iframe = re.search(r'recaptcha.*?k=([A-Za-z0-9_-]+)', html)
        if iframe:
            params["sitekey"] = iframe.group(1)

    # Sitekey from grecaptcha.render
    if "sitekey" not in params:
        render = re.search(r'sitekey\s*:\s*["\']([A-Za-z0-9_-]+)', html)
        if render:
            params["sitekey"] = render.group(1)

    # Version detection
    if re.search(r'data-size=["\']invisible', html):
        params["invisible"] = True
    if 'enterprise.js' in html:
        params["enterprise"] = True

    # Action (v3)
    action = re.search(
        r'action\s*:\s*["\']([^"\']+)',
        html[html.find('grecaptcha.execute'):] if 'grecaptcha.execute' in html else ''
    )
    if action:
        params["action"] = action.group(1)

    # data-s
    ds = re.search(r'data-s=["\']([^"\']+)', html)
    if ds:
        params["data_s"] = ds.group(1)

    # Callback
    cb = re.search(r'data-callback=["\'](\w+)', html)
    if cb:
        params["callback"] = cb.group(1)

    return params

# Usage
params = extract_recaptcha_params("https://staging.example.com/qa-login")
for k, v in params.items():
    print(f"  {k}: {v}")

Resultado esperado:

  pageurl: https://staging.example.com/qa-login
  sitekey: 6Le-SITEKEY-abc123
  invisible: True
  callback: onCaptchaComplete

Como enviar os parâmetros extraídos para a CaptchaAI

Com params preenchido, monte o corpo da requisição para o endpoint in.php, incluindo só os campos que a versão detectada precisa:

data = {
    "key": API_KEY,
    "method": "userrecaptcha",
    "googlekey": params["sitekey"],
    "pageurl": params["pageurl"],
    "json": "1",
}

if params.get("invisible"):
    data["invisible"] = "1"
if params.get("enterprise"):
    data["enterprise"] = "1"
if params.get("action"):
    data["action"] = params["action"]
if params.get("data_s"):
    data["data-s"] = params["data_s"]

resp = requests.post("https://ocr.captchaai.com/in.php", data=data).json()

Problemas comuns na extração e como resolver

Estes são os erros mais frequentes ao automatizar essa extração em produção:

  • Nenhuma sitekey encontrada — a página usa renderização dinâmica; use Puppeteer ou Selenium em vez de HTML estático.
  • Sitekey errada — várias instâncias de reCAPTCHA na mesma página; confira qual widget corresponde ao formulário que você está enviando.
  • Action não encontrado — definido em um arquivo JS externo; baixe e pesquise nos arquivos JavaScript vinculados.
  • data-s muda a cada requisição — o Google regenera o valor; extraia um data-s novo antes de cada envio.

Contexto para quem testa a partir do Brasil

Se os workers de QA rodam a partir de sa-east-1 (São Paulo) na AWS, a latência extra para buscar HTML hospedado nos EUA ou na Europa fica na casa de poucas centenas de milissegundos — irrelevante perto do tempo de resolução do CAPTCHA.

O ponto que merece atenção é outro: ao salvar HTML capturado para depuração ou logs de teste, revise com cuidado o que está sendo armazenado e por quanto tempo.

A LGPD se aplica à coleta e retenção de dados de páginas de terceiros, sobretudo quando a página capturada tem formulários com campos de usuário. Trate HTML de QA como dado sensível.

Perguntas frequentes

Preciso abrir um navegador para extrair a sitekey?

Não. Na maioria dos sites a sitekey já vem no HTML estático — dá para extrair só com requests e regex. Um navegador headless com Puppeteer ou Selenium só entra em cena quando o widget é montado via JavaScript, como em single-page applications.

A sitekey é a mesma coisa que a chave de API da CaptchaAI?

Não. A sitekey é pública, pertence ao site que exibe o reCAPTCHA e fica visível no código-fonte. A chave de API é privada, pertence à sua conta na CaptchaAI e nunca deve aparecer em HTML nem em repositórios públicos.

Por que o data-s muda a cada carregamento da página?

O Google regenera esse valor a cada requisição em sites com reCAPTCHA vinculado à própria conta Google. Extraia um data-s novo logo antes de cada envio à CaptchaAI — reaproveitar um valor antigo derruba a taxa de sucesso.

Como sei se o site usa reCAPTCHA v3 ou Enterprise em vez do v2?

v3 e Enterprise não têm widget visível — não existe checkbox nem quebra-cabeça na tela. Procure na URL do script: recaptcha/enterprise.js indica Enterprise; o parâmetro render= na URL de recaptcha/api.js indica v3.

É seguro rodar essa extração contra páginas de terceiros?

Só em ambientes que você tem autorização para testar — staging, contas próprias de QA ou páginas configuradas para isso. Ao registrar HTML capturado, considere as obrigações da LGPD sobre retenção e descarte desses dados.


Envie os parâmetros para a CaptchaAI e resolva com confiança

Depois de extrair sitekey, action, data-s e a flag enterprise, monte a requisição para a API da CaptchaAI. Crie sua chave em captchaai.com — o plano BASIC (US$ 15/mês, 5 threads) já é suficiente para validar o fluxo antes de escalar.

Guias relacionados

Os comentários estão desativados para este artigo.