DevOps & Scaling

Integração com funções do Google Cloud + CaptchaAI

Para resolver CAPTCHA no Google Cloud Functions, a receita é curta: uma função HTTP em Python que recebe method e params, busca a chave de API no Secret Manager, chama a CaptchaAI e devolve o token — sem VM para manter no ar, sem patch de sistema operacional, faturamento por execução. Este guia mostra o setup completo em três etapas: a função de resolução, o deploy no GCP e o processamento em lote via Pub/Sub para quem envia CAPTCHA em volume.


Antes de começar

Você vai precisar de:

  • Uma conta CaptchaAI ativa e a chave de API em mãos
  • Projeto no GCP com faturamento ativado e a Cloud Functions API habilitada
  • gcloud CLI autenticado (gcloud auth login) e o projeto padrão configurado
  • Python 3.11 para acompanhar os exemplos como estão — a mesma API funciona com os SDKs de Node.js, PHP, Go, Java, C#, Ruby, Rust e Kotlin

Etapa 1: crie a função HTTP que resolve o CAPTCHA

A função abaixo é o núcleo da integração. Ela lê method e params do corpo da requisição, busca a chave da CaptchaAI no Secret Manager (nunca em texto puro no código) e chama _solve(), que faz o envio para in.php e consulta res.php a cada 5 segundos até o token voltar ou o tempo limite estourar:

# main.py
import json
import time
import urllib.request
import urllib.parse
import functions_framework


@functions_framework.http
def solve_captcha(request):
    """HTTP Cloud Function for CAPTCHA solving."""
    # Parse request
    request_json = request.get_json(silent=True)
    if not request_json:
        return json.dumps({"error": "JSON body required"}), 400

    method = request_json.get("method", "userrecaptcha")
    params = request_json.get("params", {})

    # Get API key from Secret Manager
    api_key = _get_secret("captchaai-key")

    try:
        token = _solve(api_key, method, params)
        return json.dumps({"token": token})
    except Exception as e:
        return json.dumps({"error": str(e)}), 500


def _get_secret(secret_id):
    """Get secret from GCP Secret Manager."""
    from google.cloud import secretmanager
    client = secretmanager.SecretManagerServiceClient()
    name = f"projects/{_get_project_id()}/secrets/{secret_id}/versions/latest"
    response = client.access_secret_version(request={"name": name})
    return response.payload.data.decode("UTF-8")


def _get_project_id():
    """Get current GCP project ID."""
    import urllib.request
    req = urllib.request.Request(
        "http://metadata.google.internal/computeMetadata/v1/project/project-id",
        headers={"Metadata-Flavor": "Google"},
    )
    with urllib.request.urlopen(req) as resp:
        return resp.read().decode()


def _solve(api_key, method, params, timeout=90):
    """Solve CAPTCHA via CaptchaAI API."""
    # Submit
    submit_data = urllib.parse.urlencode({
        "key": api_key,
        "method": method,
        "json": 1,
        **params,
    }).encode()

    req = urllib.request.Request(
        "https://ocr.captchaai.com/in.php",
        data=submit_data,
    )
    with urllib.request.urlopen(req, timeout=30) as resp:
        result = json.loads(resp.read())

    if result.get("status") != 1:
        raise RuntimeError(f"Submit error: {result.get('request')}")

    task_id = result["request"]

    # Poll
    start = time.time()
    while time.time() - start < timeout:
        time.sleep(5)
        poll_url = (
            f"https://ocr.captchaai.com/res.php"
            f"?key={api_key}&action=get&id={task_id}&json=1"
        )
        with urllib.request.urlopen(poll_url, timeout=15) as resp:
            data = json.loads(resp.read())

        if data["request"] != "CAPCHA_NOT_READY":
            if data.get("status") == 1:
                return data["request"]
            raise RuntimeError(f"Solve error: {data['request']}")

    raise TimeoutError("Solve timeout")

Dependências do projeto

Duas linhas bastam — a função usa só a biblioteca padrão do Python para chamar a CaptchaAI, então o cold start fica leve:

# requirements.txt
functions-framework==3.*
google-cloud-secret-manager==2.*

Etapa 2: implante a função no Google Cloud Functions

Primeiro grave a chave da CaptchaAI no Secret Manager, depois publique a função com gcloud functions deploy. O --max-instances=100 evita que um pico de tráfego gere uma fatura surpresa, e o --timeout=120s dá folga para tipos de CAPTCHA mais lentos:

# Create secret
echo -n "YOUR_API_KEY" | gcloud secrets create captchaai-key --data-file=-

# Deploy function
gcloud functions deploy solve-captcha \
  --gen2 \
  --runtime=python311 \
  --region=us-central1 \
  --source=. \
  --entry-point=solve_captcha \
  --trigger-http \
  --allow-unauthenticated \
  --timeout=120s \
  --memory=256MB \
  --max-instances=100

# Test
curl -X POST https://us-central1-PROJECT.cloudfunctions.net/solve-captcha \
  -H "Content-Type: application/json" \
  -d '{
    "method": "userrecaptcha",
    "params": {
      "googlekey": "SITE_KEY",
      "pageurl": "https://example.com"
    }
  }'

Sobre a região: o comando acima usa us-central1 porque é a região mais barata e mais estável do catálogo do GCP para Cloud Functions Gen2. Se o seu público final estiver no Brasil, troque por southamerica-east1 (São Paulo) — isso reduz o RTT entre quem chama a função e o Google, mas não muda o tempo de resolução do CAPTCHA em si, que depende do tipo de desafio, não da região do seu código. Meça as duas antes de decidir.


Etapa 3: processe lotes de CAPTCHA com Pub/Sub

Chamar a função HTTP tarefa por tarefa funciona para volume baixo, mas não escala para milhares de envios. A alternativa é publicar cada tarefa num tópico do Pub/Sub e deixar uma segunda função, acionada por evento, processar em paralelo — o resultado sai por outro tópico, pronto para um worker consumir:

import base64
import json
import functions_framework
from google.cloud import pubsub_v1


@functions_framework.cloud_event
def process_captcha_task(cloud_event):
    """Process CAPTCHA task from Pub/Sub message."""
    data = base64.b64decode(cloud_event.data["message"]["data"])
    task = json.loads(data)

    api_key = _get_secret("captchaai-key")

    try:
        token = _solve(api_key, task["method"], task["params"])
        # Publish result
        publisher = pubsub_v1.PublisherClient()
        topic = f"projects/{_get_project_id()}/topics/captcha-results"
        publisher.publish(topic, json.dumps({
            "task_id": task["id"],
            "status": "success",
            "token": token,
        }).encode())

    except Exception as e:
        print(f"Task {task.get('id')} failed: {e}")

Implantar para Pub/Sub:

gcloud functions deploy process-captcha-task \
  --gen2 \
  --runtime=python311 \
  --trigger-topic=captcha-tasks \
  --timeout=120s \
  --memory=256MB

Alimente a fila a partir de outro processo

Para popular o tópico a partir de um scraper, um job agendado ou outra função, publique diretamente com o SDK do Pub/Sub:

from google.cloud import pubsub_v1
import json

publisher = pubsub_v1.PublisherClient()
topic = "projects/YOUR_PROJECT/topics/captcha-tasks"

# Submit batch
urls = ["https://site1.com", "https://site2.com", "https://site3.com"]
for i, url in enumerate(urls):
    task = {
        "id": f"task-{i}",
        "method": "userrecaptcha",
        "params": {"googlekey": "SITE_KEY", "pageurl": url},
    }
    publisher.publish(topic, json.dumps(task).encode())
    print(f"Published task-{i}")

O tamanho do plano da CaptchaAI que faz sentido aqui depende de quantas mensagens o Pub/Sub entrega ao mesmo tempo, não do total diário — cada tarefa em voo ocupa uma thread até o token voltar. Para picos de algumas dezenas de mensagens simultâneas, ADVANCE (US$ 90/mês, 50 threads) costuma sobrar; filas maiores pedem PREMIUM (US$ 170/mês, 100 threads) ou CORPORATE (US$ 240/mês, 150 threads).


Cloud Functions ou VM sempre ligada: o que custa menos

A resposta muda com o volume. Em baixo volume, o faturamento por execução do Cloud Functions é uma fração do custo de manter uma VM ligada 24 horas; a partir de um certo ponto, as curvas se cruzam:

Fator Funções de nuvem VM sempre ativa
100 resolve/day ~$0,01/day ~$1,00/day
1.000 soluções/day ~$0,10/day ~$1,00/day
10.000 soluções/day ~$1,00/day ~$1,00/day
Custo ocioso US$ 0 Custo total da VM
Partida a frio ~300ms Nenhum

Na prática: abaixo de ~10 mil solves por dia, o Cloud Functions sai mais barato e você não paga nada nos horários sem tráfego. Acima disso, os custos empatam e a decisão passa a ser operacional — o cold start de ~300 ms raramente importa em automação.


Erros comuns ao integrar a CaptchaAI ao Cloud Functions

Problema Causa Correção
A função expira Tempo limite muito curto Definir --timeout=120s
Permissão negada em segredo Função do IAM ausente Conceder secretmanager.secretAccessor
Alta latência de partida a frio Grandes dependências Use urllib em vez de requests
Novas tentativas de mensagem Pub/Sub Erro ao retornar função Retornar sucesso para erros que não podem ser repetidos

Vale reforçar o último ponto: se a função levantar uma exceção não tratada, o Pub/Sub reentrega a mensagem — e o mesmo CAPTCHA acaba enviado à CaptchaAI mais de uma vez. Capture os erros esperados dentro de process_captcha_task, registre no log e devolva sucesso mesmo quando a resolução falhar.


Perguntas frequentes sobre CAPTCHA no Google Cloud Functions

Gen1 ou Gen2 no Cloud Functions?

Use Gen2. Ele suporta tempos limite mais longos (até 60 minutos), mais memória e concorrência — tudo isso ajuda quando um CAPTCHA demora mais do que o esperado para resolver.

Como evito cold start toda vez que a função fica ociosa?

Use o Cloud Scheduler para chamar a função a cada 5 minutos, ou defina --min-instances=1 para manter uma instância sempre quente — isso custa cerca de US$ 7/mês a mais e só compensa se a latência da primeira chamada for crítica para o seu fluxo.

Vale a pena implantar em southamerica-east1 para reduzir latência?

Só se o seu público final estiver no Brasil e a latência de rede até o GCP for o gargalo. A localização física dos servidores da CaptchaAI não é documentada publicamente, então trocar a região do Cloud Functions reduz o RTT até o Google, mas não necessariamente até a CaptchaAI — meça antes de assumir qual região é mais rápida na prática.

Quantas threads da CaptchaAI preciso para um pico de tráfego no Cloud Functions?

Depende de quantas tarefas ficam em voo ao mesmo tempo, não do volume diário total. BASIC (US$ 15/mês, 5 threads) cobre testes e volume baixo; para picos de dezenas de chamadas simultâneas via Pub/Sub, ADVANCE (US$ 90/mês, 50 threads) costuma ser o ponto de partida certo — acompanhe o uso e migre de plano se as threads começarem a ficar saturadas.

Preciso me preocupar com a LGPD ao logar as respostas da função?

Se os params enviados à CaptchaAI contiverem dados de formulários com informação pessoal, sim — trate os logs do Cloud Functions como dado sensível: evite gravar params completos, mascare o que for identificável e defina uma política de retenção. As mesmas obrigações valem sob a RGPD para tráfego originado em Portugal.


Guias relacionados


Sem servidor no GCP — obtenha sua chave da CaptchaAI hoje mesmo.

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