Manter uma VM ligada 24 horas por dia só para resolver CAPTCHA custa caro e complica o deploy. O Azure Functions resolve isso de outro jeito: você paga pelo tempo de execução, o Key Vault guarda a chave da API com segurança, a fila do Azure distribui tarefas em lote e o Application Insights mostra cada falha de resolução em tempo real. Este guia mostra o setup completo em três etapas — function HTTP, processamento em lote e deploy — com código Python pronto para copiar.
Antes de começar
Você vai precisar de:
- Uma conta CaptchaAI ativa, com a chave de API em mãos
- Assinatura do Azure com permissão para criar resource group, Function App e Key Vault
- Azure CLI autenticado (
az login) e o Azure Functions Core Tools instalado - Python 3.11 para seguir 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 — resolva o CAPTCHA com um HTTP trigger
O ponto de entrada é uma function HTTP direta: recebe o method e os params da API da CaptchaAI no corpo da requisição, chama solve() e devolve o token em JSON. Se a submissão ou o polling falharem, o erro vai para o log e a resposta volta com status 500 — sem exceção não tratada derrubando a function.
# function_app.py
import json
import time
import os
import logging
import urllib.request
import urllib.parse
import azure.functions as func
app = func.FunctionApp()
@app.route(route="solve", methods=["POST"])
def solve_captcha(req: func.HttpRequest) -> func.HttpResponse:
"""HTTP trigger for CAPTCHA solving."""
try:
body = req.get_json()
except ValueError:
return func.HttpResponse(
json.dumps({"error": "JSON body required"}),
status_code=400,
mimetype="application/json",
)
method = body.get("method", "userrecaptcha")
params = body.get("params", {})
api_key = os.environ["CAPTCHAAI_KEY"]
try:
token = solve(api_key, method, params)
return func.HttpResponse(
json.dumps({"token": token}),
mimetype="application/json",
)
except Exception as e:
logging.error(f"Solve failed: {e}")
return func.HttpResponse(
json.dumps({"error": str(e)}),
status_code=500,
mimetype="application/json",
)
def solve(api_key, method, params, timeout=90):
"""Solve CAPTCHA via CaptchaAI API."""
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"]
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")
Proteja a chave no Key Vault
Nunca deixe a chave da CaptchaAI em texto puro em produção. Armazene no Azure Key Vault e conceda acesso à identidade gerenciada da function:
# Create Key Vault
az keyvault create \
--name captchaai-vault \
--resource-group myResourceGroup
# Store secret
az keyvault secret set \
--vault-name captchaai-vault \
--name CaptchaAIKey \
--value "YOUR_API_KEY"
# Grant function access
az webapp identity assign \
--name my-captcha-function \
--resource-group myResourceGroup
az keyvault set-policy \
--name captchaai-vault \
--object-id <principal-id> \
--secret-permissions get
Depois, referencie a chave direto no app setting, sem copiar o valor para nenhum arquivo do repositório:
CAPTCHAAI_KEY=@Microsoft.KeyVault(SecretUri=https://captchaai-vault.vault.azure.net/secrets/CaptchaAIKey/)
Etapa 2 — processe lotes de CAPTCHA pela fila do Azure
Para volume alto, não chame a function HTTP tarefa por tarefa. Publique cada uma na fila captcha-tasks e deixe o trigger de fila processar em paralelo, respeitando o número de threads do seu plano CaptchaAI:
@app.queue_trigger(
arg_name="msg",
queue_name="captcha-tasks",
connection="AzureWebJobsStorage",
)
def process_queue_task(msg: func.QueueMessage):
"""Process CAPTCHA task from queue."""
task = json.loads(msg.get_body().decode())
api_key = os.environ["CAPTCHAAI_KEY"]
try:
token = solve(api_key, task["method"], task["params"])
logging.info(f"Task {task['id']} solved")
# Store result in Table Storage or return queue
_store_result(task["id"], "success", token)
except Exception as e:
logging.error(f"Task {task['id']} failed: {e}")
_store_result(task["id"], "error", str(e))
def _store_result(task_id, status, value):
"""Store result (simplified — use Table Storage in production)."""
logging.info(f"Result: {task_id} = {status}")
Organize os arquivos do projeto
Um projeto mínimo de Azure Functions em Python tem quatro arquivos:
captcha-function/
├── function_app.py
├── requirements.txt
├── host.json
└── local.settings.json
requirements.txt:
azure-functions
host.json:
Ajuste o functionTimeout se as tarefas mais lentas — grade de imagens, por exemplo — passarem dos 2 minutos padrão. É a causa mais comum de timeout silencioso em produção:
{
"version": "2.0",
"functionTimeout": "00:02:00",
"logging": {
"logLevel": {
"default": "Information"
}
}
}
local.settings.json:
{
"IsEncrypted": false,
"Values": {
"FUNCTIONS_WORKER_RUNTIME": "python",
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"CAPTCHAAI_KEY": "YOUR_API_KEY_FOR_LOCAL_DEV"
}
}
Etapa 3 — implante e valide em produção
Crie o resource group, o storage account e a function app, depois publique com o Azure Functions Core Tools:
Dica de latência: se o público final estiver na América Latina, troque
westus2porbrazilsouthno comando abaixo — a function fica fisicamente mais perto de quem chama a API, o que reduz o RTT percebido pelo usuário final. Meça o RTT até o endpoint da CaptchaAI a partir de cada região antes de decidir: a localização real dos servidores da CaptchaAI não é documentada publicamente, então não assuma qual região fica mais perto sem testar.
# Create function app
az functionapp create \
--resource-group myResourceGroup \
--consumption-plan-location westus2 \
--runtime python \
--runtime-version 3.11 \
--functions-version 4 \
--name my-captcha-solver \
--storage-account mystorageaccount
# Deploy
func azure functionapp publish my-captcha-solver
# Test
curl -X POST https://my-captcha-solver.azurewebsites.net/api/solve \
-H "Content-Type: application/json" \
-d '{
"method": "userrecaptcha",
"params": {
"googlekey": "SITE_KEY",
"pageurl": "https://example.com"
}
}'
Alimente a fila a partir de outro processo
Para popular a fila a partir de outro processo — um scraper, um job agendado — use o SDK do Azure Storage Queue:
from azure.storage.queue import QueueClient
import json
queue = QueueClient.from_connection_string(
conn_str="YOUR_STORAGE_CONNECTION_STRING",
queue_name="captcha-tasks",
)
# Submit batch
for i in range(10):
task = {
"id": f"task-{i}",
"method": "userrecaptcha",
"params": {
"googlekey": "SITE_KEY",
"pageurl": f"https://example.com/page{i}",
},
}
queue.send_message(json.dumps(task))
print(f"Queued task-{i}")
Problemas comuns e como resolver
| Problema | Causa | Correção |
|---|---|---|
| A function estoura em 5 minutos | Timeout padrão do host | Ajuste functionTimeout no host.json |
| Referência do Key Vault volta vazia | Identidade gerenciada ou policy ausente | Atribua a managed identity e a policy do Key Vault |
| Mensagens da fila repetem sem parar | A function lança exceção não tratada | Capture os erros conhecidos, registre e retorne normalmente |
| Cold start acima de 10 segundos | Inicialização do runtime Python | Use o plano Premium ou defina FUNCTIONS_WORKER_PROCESS_COUNT |
Perguntas frequentes sobre CAPTCHA no Azure Functions
Qual plano da CaptchaAI combina com o Azure Functions?
Depende de quantas tarefas rodam ao mesmo tempo, não do total de solves — a CaptchaAI cobra por thread, com solves ilimitados dentro de cada uma:
- BASIC (US$ 15/mês, 5 threads) — cobre bem testes e volume baixo, com a function rodando no modo Consumption do Azure
- ADVANCE (US$ 90/mês, 50 threads) — filas com dezenas de tarefas simultâneas
- PREMIUM (US$ 170/mês, 100 threads) — se a function já roda no plano Premium do Azure com carga constante, para não esperar threads liberarem
Uso o plano Consumption ou o Premium do Azure Functions?
Consumption para volume baixo (menos de 100 tarefas por dia) — você paga só pelo que executar. Para carga constante, o Premium compensa: mantém instâncias aquecidas, elimina o cold start e permite integração com VNET.
Como evito que a fila reprocesse a mesma tarefa CAPTCHA várias vezes?
Trate os erros esperados dentro da function e sempre chame _store_result, mesmo quando a resolução falha. Deixar uma exceção subir sem tratamento faz o Azure Queue Storage reenviar a mensagem automaticamente até o limite de tentativas — capturar e registrar o erro, como no exemplo acima, corta esse loop.
O cold start do Python atrapalha o tempo de resposta do CAPTCHA?
No plano Consumption, pode atrapalhar: a primeira chamada depois de um período ocioso leva mais de 10 segundos só para o runtime do Python subir, antes mesmo de a function chamar a API da CaptchaAI. Se isso pesar no seu SLA, use o plano Premium ou ajuste FUNCTIONS_WORKER_PROCESS_COUNT.
O Durable Functions ajuda a resolver vários CAPTCHAs em paralelo?
Sim. O padrão fan-out/fan-in é feito para isso: dispare várias chamadas de solve() de uma vez — por exemplo, 10 CAPTCHAs em paralelo — e uma function separada coleta todos os resultados quando terminam. Funciona melhor do que orquestrar isso na mão pela fila.
Guias relacionados
Implante no Azure — obtenha sua chave da CaptchaAI hoje mesmo.