DevOps y Escalado

AWS Lambda + CaptchaAI: resolución de CAPTCHA sin servidor

AWS Lambda maneja la resolución de CAPTCHA sin administrar servidores. Pague solo al resolver, escale automáticamente e intégrelo con API Gateway, SQS o Step Functions.


Controlador Lambda

# lambda_function.py
import json
import os
import time
import urllib.request
import urllib.parse


def lambda_handler(event, context):
    """AWS Lambda handler for CaptchaAI solving."""
    api_key = os.environ["CAPTCHAAI_KEY"]

    # Parse input
    body = json.loads(event.get("body", "{}")) if isinstance(event.get("body"), str) else event

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

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


def solve_captcha(api_key, method, params, timeout=90):
    """Solve CAPTCHA using CaptchaAI API."""
    # Submit task
    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 for result
    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")

Clave API segura con Secrets Manager

import json
import boto3


def get_api_key():
    """Retrieve CaptchaAI key from AWS Secrets Manager."""
    client = boto3.client("secretsmanager")
    response = client.get_secret_value(SecretId="captchaai/api-key")
    secret = json.loads(response["SecretString"])
    return secret["api_key"]

Guarda el secreto:

aws secretsmanager create-secret \
  --name captchaai/api-key \
  --secret-string '{"api_key":"YOUR_API_KEY"}'

Plantilla SAM (infraestructura como código)

# template.yaml
AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31

Globals:
  Function:
    Timeout: 120
    MemorySize: 256
    Runtime: python3.11

Resources:
  CaptchaSolverFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: lambda_function.lambda_handler
      Environment:
        Variables:
          CAPTCHAAI_KEY: !Sub "{{resolve:secretsmanager:captchaai/api-key:SecretString:api_key}}"
      Events:
        SolveApi:
          Type: Api
          Properties:
            Path: /solve
            Method: post
      Policies:

        - AWSSecretsManagerGetSecretValuePolicy:
            SecretArn: !Sub "arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:captchaai/api-key-*"

Outputs:
  SolveApiUrl:
    Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/solve"

Implementar

# Build and deploy
sam build
sam deploy --guided

# Test
curl -X POST https://YOUR_API_ID.execute-api.us-east-1.amazonaws.com/Prod/solve \
  -H "Content-Type: application/json" \
  -d '{
    "method": "userrecaptcha",
    "params": {
      "googlekey": "SITE_KEY",
      "pageurl": "https://example.com"
    }
  }'

Procesamiento por lotes activado por SQS

Procese tareas CAPTCHA desde una cola SQS:

import json
import os
import time
import urllib.request
import urllib.parse


def sqs_handler(event, context):
    """Process CAPTCHA tasks from SQS queue."""
    api_key = os.environ["CAPTCHAAI_KEY"]
    results = []

    for record in event["Records"]:
        task = json.loads(record["body"])
        try:
            token = solve_captcha(
                api_key,
                task["method"],
                task["params"],
            )
            results.append({
                "task_id": task.get("id"),
                "status": "success",
                "token": token[:50],
            })
        except Exception as e:
            results.append({
                "task_id": task.get("id"),
                "status": "error",
                "error": str(e),
            })

    return {"results": results}

Consideraciones sobre Lambda

Factor Valor
Tiempo de espera máximo 15 minutos (configurado en 2 minutos para la mayoría de los CAPTCHA)
Memoria 256 MB suficientes (sin procesamiento pesado)
Simultaneidad Predeterminado 1000 simultáneos (solicite aumento si es necesario)
Arranque en frío ~500 ms para Python (insignificante frente al tiempo de resolución)
Costo ~$0.0001 por solución (solo cálculo)
Dependencias Utilice urllib (integrado) para evitar capas Lambda

Solución de problemas

Problema causa Solución
La función se agota Tiempo de espera de Lambda <tiempo de resolución Establecer el tiempo de espera en 120 s+
Permiso denegado en secreto Falta la política de IAM Agregar política de lectura de SecretsManager
El arranque en frío añade latencia Invocaciones poco frecuentes Usar simultaneidad aprovisionada
Error de importación para solicitudes No incluido en Lambda Utilice urllib.request (integrado) o agregue capa

Preguntas frecuentes

¿Es Lambda rentable para resolver CAPTCHA?

Sí. A ~$0,0001 por invocación (256 MB, 60 segundos), Lambda agrega un costo insignificante además de la tarifa de la API CaptchaAI. Evitas costes del servidor durante el tiempo de inactividad.

¿Qué pasa con el tiempo de espera de 15 minutos de Lambda?

La mayoría de los CAPTCHA se resuelven en 10 a 60 segundos. Establezca su tiempo de espera de Lambda en 120 segundos. Para tipos complejos como reCAPTCHA Enterprise, utilice 180 segundos.

¿Puedo usar capas Lambda para la biblioteca de solicitudes?

Sí, pero urllib.request (integrado) funciona bien para la sencilla API HTTP de CaptchaAI. Esto evita por completo la gestión de capas.


Guías relacionadas

  • Funciones de Google Cloud + CaptchaAI
  • Funciones de Azure + CaptchaAI

Pasa a serverless: obtén tu API key de CaptchaAI hoy.

Los comentarios están deshabilitados para este artículo.