Se a tarefa BLS CAPTCHA volta com ERROR_BAD_PARAMETERS mesmo com sitekey e pageurl corretos, o problema quase nunca está nesses dois campos — está em instructions e code, os parâmetros opcionais que a maioria dos tutoriais ignora. O BLS CAPTCHA aparece com frequência em portais de agendamento, como o fluxo de marcação de vistos operado pela BLS International, e cada implementação varia o texto do desafio conforme a sessão, o idioma ou a região atendida.
Este guia mostra como extrair instructions e code de uma página real, quando vale a pena enviá-los à API da CaptchaAI e como montar um fluxo completo com Selenium — do carregamento até o envio do formulário.
Parâmetros do BLS CAPTCHA: o que a API espera
A API da CaptchaAI aceita seis parâmetros para o método bls: três obrigatórios e três opcionais — instructions, code e json — que ajudam quando o desafio tem texto ambíguo ou uma variante pouco comum:
| Parâmetro | Obrigatório | Tipo | Descrição |
|---|---|---|---|
method |
Sim | String | Deve ser bls |
sitekey |
Sim | String | A chave BLS CAPTCHA do site |
pageurl |
Sim | String | URL da página que exibe o CAPTCHA |
instructions |
Não | String | Texto do enunciado extraído da imagem do CAPTCHA |
code |
Não | String | Identificador da variante do desafio BLS CAPTCHA |
json |
Não | Inteiro | Defina como 1 para receber a resposta em JSON |
Na prática, method, sitekey e pageurl já bastam para a maioria dos desafios. Reserve os outros dois para quando a tarefa voltar rejeitada com frequência.
Como extrair sitekey, instructions e code da página
O primeiro passo é sempre ler o DOM antes de enviar qualquer coisa à CaptchaAI. A função abaixo abre a página com Selenium, localiza o widget pelo atributo data-sitekey, captura o texto de instrução visível e, quando o code está embutido no HTML ou em um script inline, extrai o valor com uma expressão regular. Se um campo não existir, a função o omite.
# 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)
O resultado é um dicionário params pronto para a função de envio da próxima seção. Rode essa extração a cada sessão: os campos opcionais podem mudar de uma página para outra.
Enviando o BLS CAPTCHA para a CaptchaAI
Envio básico
Com os parâmetros em mãos, o envio segue o padrão de qualquer tarefa CaptchaAI: POST para in.php, seguido de polling em res.php até o status mudar para 1. A função abaixo só adiciona instructions e code quando eles existem.
# 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}")
Repare no intervalo de 10 segundos antes do primeiro polling: o BLS CAPTCHA resolve em menos de 1 segundo no worker da CaptchaAI, com alta taxa de sucesso nos tipos suportados — a espera cobre a fila e a latência de rede, não o tempo de resolução.
O parâmetro instructions: quando ele muda o resultado
instructions existe porque nem todo desafio BLS embute o enunciado na própria imagem. Quando o texto aparece como elemento HTML separado, repassá-lo à CaptchaAI reduz a ambiguidade e melhora a precisão. Em portais de agendamento de visto, o enunciado costuma mudar conforme o idioma do consulado ou a região — por isso a extração deve rodar a cada sessão, nunca a partir de um valor fixo salvo no código.
# 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
Times de QA de agências de viagens no Brasil e em Portugal costumam replicar esse fluxo em staging antes de liberar uma nova versão do formulário: variam o enunciado do desafio e conferem se o instructions extraído bate com o texto exibido na tela — uma forma barata de detectar mudanças de redação antes que derrubem a taxa de acerto em produção.
O parâmetro code: identificando a variante do desafio
Nota: algumas implementações de BLS CAPTCHA usam mais de uma variante de desafio na mesma página, cada uma identificada por um
code. A função abaixo tenta três padrões comuns —captchaTypeno JavaScript, o atributodata-captcha-codeno HTML e a variávelbls_codeno script — e retorna o primeiro valor encontrado. Assim comoinstructions, ocodenão é constante: sites multi-idioma costumam alternar a variante conforme a sessão, então reextrair a cada carregamento é a prática correta.
# 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
Fluxo completo com Selenium: da página ao envio do formulário
Juntando as peças anteriores, a função abaixo cobre o ciclo inteiro: abre a página, preenche o formulário (quando houver), extrai sitekey e instructions do widget, resolve o desafio via API, injeta o token no campo esperado e envia. A injeção cobre dois cenários — um input já existente ou a criação de um campo oculto — porque cada implementação nomeia o campo de resposta de um jeito diferente.
# 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
Essa função depende de solve_bls, definida na seção de envio básico — mantenha as duas no mesmo módulo antes de rodar o fluxo completo.
Resolvendo problemas comuns
A maioria dos erros de BLS CAPTCHA cai em uma destas quatro categorias. Antes de investigar mais fundo, confirme se sitekey e pageurl foram extraídos do elemento correto — é a causa mais comum de rejeição.
| Problema | Causa provável | Como corrigir |
|---|---|---|
ERROR_BAD_PARAMETERS |
Faltou sitekey ou pageurl no payload |
Confirme a extração de ambos antes do envio |
| Solução rejeitada pelo site | Desafio ambíguo sem instructions |
Envie instructions para desafios com enunciado pouco claro |
| Tipo de CAPTCHA errado detectado | O widget não é um BLS CAPTCHA | Verifique se não é reCAPTCHA ou um desafio personalizado do site |
sitekey não encontrado |
O widget carrega de forma assíncrona | Aguarde o elemento renderizar antes de extrair os parâmetros |
Perguntas frequentes
Preciso enviar instructions em toda tarefa BLS?
Não. A CaptchaAI resolve a maioria dos BLS CAPTCHAs sem esse parâmetro. Envie instructions quando o desafio tiver um enunciado específico e a solução voltar rejeitada com frequência — é aí que ele realmente melhora a precisão.
O parâmetro code muda entre sessões ou por região atendida?
Sim, com frequência. Trate code como um valor de sessão, não como uma constante: reextraia-o a cada carregamento de página, principalmente em portais que atendem mais de um idioma ou país.
Por que a CaptchaAI retorna ERROR_BAD_PARAMETERS mesmo com a sitekey preenchida?
Confira o pageurl: ele precisa ser exatamente a URL onde o widget foi renderizado, sem parâmetros de sessão soltos nem redirecionamentos intermediários — é a segunda causa mais comum desse erro.
BLS CAPTCHA e reCAPTCHA aparecem no mesmo fluxo de agendamento. Como sei qual estou resolvendo?
Verifique o atributo do widget antes de montar o payload: o BLS CAPTCHA expõe data-sitekey numa div com classe .bls-captcha, enquanto o reCAPTCHA usa atributos próprios do Google. Enviar method=bls para um desafio que é reCAPTCHA sempre resulta em erro.
Guias relacionados
Para aprofundar em tópicos vizinhos ao BLS CAPTCHA, veja também:
Domine os parâmetros do BLS CAPTCHA — comece com a CaptchaAI.