Tutoriales de API

Parámetros instructions y code de BLS CAPTCHA a fondo

Con sitekey y pageurl basta para enviar un BLS CAPTCHA a CaptchaAI, pero son los dos parámetros opcionales —instructions y code— los que marcan la diferencia entre una integración que falla de forma intermitente y una que resuelve de forma estable. Los portales de BLS, muy usados para solicitar citas de visado en centros que atienden a solicitantes de toda Latinoamérica y España, muestran desafíos de imágenes cuyo enunciado cambia según la variante.

Estos son los dos parámetros que casi nadie configura bien y que este artículo desglosa:

  • instructions: el enunciado en texto del desafío. Opcional, pero decisivo cuando ese texto no está incrustado dentro de la imagen.
  • code: el identificador de la variante de BLS. Solo lo necesitas cuando un centro despliega varios tipos de desafío a la vez.

A continuación verás qué hace cada uno, cuándo conviene pasarlo y cómo extraerlo de la página antes de enviarlo a la API.


Referencia de parámetros de la API BLS

Estos son los seis campos que acepta el método bls. Solo los tres primeros son obligatorios; el resto ajusta la precisión.

Parámetro Requerido Tipo Descripción
method cadena Debe ser bls
sitekey cadena La clave BLS CAPTCHA del sitio
pageurl cadena URL de la página que muestra el CAPTCHA
instructions No cadena Texto del enunciado de la imagen CAPTCHA
code No cadena Identificador o tipo de BLS CAPTCHA
json No entero Ponlo en 1 para recibir respuestas JSON

Cómo extraer sitekey, instructions y code de la página

Antes de enviar nada necesitas leer tres valores directamente del DOM:

  • sitekey: en el atributo data-sitekey del contenedor del desafío.
  • instructions: en el elemento de texto que acompaña a la cuadrícula de imágenes.
  • code: embebido en el HTML o en un script, cuando el portal lo usa.

Esta función los recoge en un solo paso, con un bloque try/except para el enunciado porque no siempre está presente:

# extract_bls.py
import re
from selenium import webdriver
from selenium.webdriver.common.by import By


def extract_bls_params(url):
    """Extract BLS CAPTCHA parameters from a page."""
    driver = webdriver.Chrome()
    driver.get(url)

    params = {"pageurl": url}

    # Extract sitekey
    captcha_el = driver.find_element(By.CSS_SELECTOR, "[data-sitekey], .bls-captcha")
    sitekey = captcha_el.get_attribute("data-sitekey")
    if sitekey:
        params["sitekey"] = sitekey

    # Extract instructions if visible
    try:
        instructions_el = driver.find_element(
            By.CSS_SELECTOR, ".captcha-instructions, .captcha-text"
        )
        params["instructions"] = instructions_el.text.strip()
    except Exception:
        pass

    # Extract code from hidden input or script
    page_source = driver.page_source
    code_match = re.search(r'captcha_code["\']?\s*[:=]\s*["\']([^"\']+)', page_source)
    if code_match:
        params["code"] = code_match.group(1)

    driver.quit()
    return params


# Usage
params = extract_bls_params("https://bls-example.com/appointment")
print(params)

Enviar el BLS CAPTCHA a CaptchaAI

Con los parámetros en mano, el envío sigue el patrón clásico de dos pasos de la API: publicas la tarea en in.php y luego sondeas el resultado en res.php. El ejemplo espera 10 segundos antes de la primera consulta y reintenta cada 5, un ritmo acorde con el tiempo de resolución típico de BLS. Fíjate en que instructions y code solo se añaden al payload si tienen valor: son opcionales por diseño.

# solve_bls_basic.py
import requests
import time
import os


def solve_bls(sitekey, pageurl, instructions=None, code=None):
    """Solve BLS CAPTCHA via CaptchaAI API."""
    api_key = os.environ["CAPTCHAAI_API_KEY"]

    payload = {
        "key": api_key,
        "method": "bls",
        "sitekey": sitekey,
        "pageurl": pageurl,
        "json": 1,
    }

    # Add optional parameters for higher accuracy
    if instructions:
        payload["instructions"] = instructions
    if code:
        payload["code"] = code

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

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

    task_id = result["request"]

    # Poll for result
    time.sleep(10)
    for _ in range(30):
        resp = requests.get("https://ocr.captchaai.com/res.php", params={
            "key": api_key,
            "action": "get",
            "id": task_id,
            "json": 1,
        }, timeout=15)
        data = resp.json()

        if data.get("status") == 1:
            return data["request"]
        if data["request"] != "CAPCHA_NOT_READY":
            raise RuntimeError(data["request"])
        time.sleep(5)

    raise TimeoutError("BLS solve timeout")


# Usage
solution = solve_bls(
    sitekey="your-bls-sitekey",
    pageurl="https://bls-example.com/appointment",
    instructions="Select images in the correct order",
)
print(f"Solution: {solution}")

El parámetro instructions: cuándo aporta precisión

El parámetro instructions le indica a CaptchaAI qué te pide exactamente el desafío. Es opcional, pero conviene pasarlo en estos casos:

  • El enunciado vive en el HTML, fuera de la imagen (por ejemplo, «selecciona las imágenes en el orden correcto»).
  • El desafío es ambiguo y admite varias interpretaciones de orden o selección.
  • Notas que la tasa de resolución baja en un tipo de desafío concreto.

Estos son los enunciados más habituales en BLS y una función que los localiza probando varios selectores hasta dar con el que renderiza el portal:

# Common BLS instruction patterns:
instructions_examples = [
    "Select images in the correct order",
    "Click the images in order from left to right",
    "Arrange the images by number",
    "Select the matching image",
    "Click in the order shown",
]

# Extract instructions from the CAPTCHA image area
def get_instructions_from_page(driver):
    """Try multiple selectors to find instruction text."""
    selectors = [
        ".captcha-instructions",
        ".bls-captcha-text",
        "#captcha-prompt",
        ".challenge-text",
    ]

    for sel in selectors:
        try:
            el = driver.find_element(By.CSS_SELECTOR, sel)
            text = el.text.strip()
            if text:
                return text
        except Exception:
            continue

    return None

El parámetro code: identificar la variante de BLS

El parámetro code identifica la variante concreta de BLS CAPTCHA. Algunos centros BLS despliegan varios tipos de desafío y los distinguen mediante un código embebido en la página. Cuando existe, extraerlo y enviarlo evita que CaptchaAI resuelva el desafío con el modelo equivocado. La detección prueba tres ubicaciones habituales del código:

# Detect BLS CAPTCHA code from page
def detect_bls_code(page_source):
    """Detect which BLS CAPTCHA code/type is being used."""
    patterns = [
        (r'captchaType["\']?\s*[:=]\s*["\'](\w+)', "captchaType"),
        (r'data-captcha-code["\']?\s*=\s*["\'](\w+)', "data attribute"),
        (r'bls_code["\']?\s*[:=]\s*["\'](\w+)', "bls_code"),
    ]

    for pattern, source in patterns:
        match = re.search(pattern, page_source)
        if match:
            return match.group(1)

    return None

Flujo completo de BLS con Selenium

Para automatizar el ciclo entero —rellenar el formulario, extraer los parámetros, resolver e inyectar el resultado en el DOM— este es el flujo de extremo a extremo con Selenium. Mantén la secuencia: primero completas los campos previos al CAPTCHA, luego lees el sitekey y el enunciado, resuelves por API e inyectas el token en el campo oculto antes de enviar el formulario.

# full_bls_flow.py
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import os
import re


def solve_bls_with_selenium(url, form_data=None):
    """Complete BLS CAPTCHA flow using Selenium."""
    driver = webdriver.Chrome()
    driver.get(url)

    wait = WebDriverWait(driver, 15)

    # Fill any form fields before CAPTCHA
    if form_data:
        for field_id, value in form_data.items():
            el = wait.until(EC.presence_of_element_located((By.ID, field_id)))
            el.clear()
            el.send_keys(value)

    # Extract CAPTCHA parameters
    captcha_container = wait.until(
        EC.presence_of_element_located((By.CSS_SELECTOR, "[data-sitekey], .bls-captcha"))
    )
    sitekey = captcha_container.get_attribute("data-sitekey")

    # Get instructions
    instructions = None
    try:
        inst_el = driver.find_element(By.CSS_SELECTOR, ".captcha-instructions")
        instructions = inst_el.text.strip()
    except Exception:
        pass

    # Solve via API
    solution = solve_bls(
        sitekey=sitekey,
        pageurl=driver.current_url,
        instructions=instructions,
    )

    # Inject solution
    driver.execute_script("""
        var input = document.querySelector('input[name="captcha-response"], #captcha-response');
        if (input) {
            input.value = arguments[0];
        } else {
            var hidden = document.createElement('input');
            hidden.type = 'hidden';
            hidden.name = 'captcha-response';
            hidden.value = arguments[0];
            document.forms[0].appendChild(hidden);
        }
    """, solution)

    # Submit form
    submit_btn = driver.find_element(By.CSS_SELECTOR, "button[type='submit'], #submit")
    submit_btn.click()

    # Wait for confirmation
    wait.until(EC.url_changes(url))
    result_url = driver.current_url
    driver.quit()

    return result_url

Errores frecuentes y cómo resolverlos

Problema Causa Solución
ERROR_BAD_PARAMETERS Falta sitekey o pageurl Verifica que ambos se extraigan correctamente
Solución rechazada No se pasaron las instrucciones Incluye el parámetro instructions en desafíos ambiguos
Tipo de CAPTCHA incorrecto No es un BLS CAPTCHA Comprueba si en realidad es un reCAPTCHA o un tipo personalizado
sitekey no encontrado Carga dinámica Espera a que el elemento CAPTCHA se renderice antes de extraerlo

La mayoría de los fallos en producción se reducen a dos causas: extraer los parámetros antes de que el desafío se haya renderizado, o no pasar instructions en un desafío que sí lo necesita. Registra siempre el payload que envías para poder reproducir el problema.


Preguntas frecuentes

¿Cómo sé si un portal usa BLS CAPTCHA y no reCAPTCHA?

Revisa el HTML del contenedor del desafío. Un BLS CAPTCHA expone su propio sitekey en un atributo data-sitekey sobre un elemento con clase bls-captcha y suele mostrar una cuadrícula de imágenes con un enunciado en texto. Si en su lugar ves un iframe de google.com/recaptcha, es un reCAPTCHA y necesitas otro método.

¿Qué significa el error ERROR_BAD_PARAMETERS al enviar el CAPTCHA?

Indica que falta el sitekey o el pageurl, o que llegan vacíos. Casi siempre ocurre cuando el CAPTCHA se carga de forma dinámica y lees los valores antes de que el elemento exista. Espera a que se renderice y vuelve a leer el atributo antes de enviar la tarea.

¿Qué plan de CaptchaAI conviene para resolver BLS CAPTCHA en volumen?

Depende de cuántos CAPTCHA resuelvas en paralelo, no del total. CaptchaAI factura por thread concurrente con resoluciones ilimitadas: el plan BASIC ($15/mes, 5 threads) cubre pruebas y flujos pequeños, mientras que ADVANCE ($90/mes, 50 threads) encaja cuando monitorizas varios portales a la vez. Consulta los precios en captchaai.com/pricing.

¿Cuánto tarda CaptchaAI en resolver un BLS CAPTCHA?

Normalmente entre 10 y 20 segundos. Por eso el ejemplo de sondeo espera 10 segundos antes de la primera consulta y luego reintenta cada 5. BLS mantiene una alta tasa de éxito en los desafíos compatibles.


Guías relacionadas


Domina los parámetros de BLS CAPTCHA: empieza con CaptchaAI.

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