Se você já tentou automatizar um formulário protegido por CAPTCHA BLS, sabe do que se trata: aparece uma grade 3x3 de imagens ao lado de um código numérico como "664", e é preciso marcar as células certas para seguir em frente — sem áudio, sem reCAPTCHA, só a grade e o código.
Neste guia você extrai as nove imagens e o código de instrução direto da página, envia tudo para a API da CaptchaAI e clica automaticamente nas células que ela retornar, com exemplos prontos em Python e JavaScript.
Como funciona o CAPTCHA BLS: grade 3x3 e código de instrução
Esse tipo de desafio é comum em portais de agendamento — o nome vem justamente dos sistemas de solicitação de visto operados pela BLS International, usados por quem marca horário de visto Schengen em países como Portugal e Espanha. Se você faz QA ou testes de integração automatizados contra um ambiente próprio ou de staging com esse padrão de grade, é exatamente isso que vai encontrar.
O CAPTCHA exibe:
- Uma grade 3x3 com 9 células de imagem
- Um código de instrução numérico (por exemplo, 664, 123, 546) que diz quais células selecionar
- Células numeradas da esquerda para a direita, de cima para baixo:
1 2 3
4 5 6
7 8 9
Você não precisa decifrar o padrão do código sozinho — ele só importa para o solucionador. A resposta da CaptchaAI é uma lista com os índices das células (de 1 a 9) que combinam com a instrução.
Passo 1: extraia a grade de imagens e o código de instrução
O primeiro passo é ler a página e capturar duas coisas: as nove imagens da grade em base64 e o texto do código de instrução.
Requisitos antes de começar:
- Seletor CSS da grade:
.captcha-grid img - Seletor CSS do texto de instrução:
.captcha-instruction - Um driver de navegador já configurado (Selenium ou Puppeteer)
Os dois exemplos abaixo cobrem os dois casos mais comuns.
Python (Selenium)
import base64
from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.get("https://example.com/bls-protected-page")
# Find the grid container
grid_cells = driver.find_elements(By.CSS_SELECTOR, ".captcha-grid img")
images = []
for cell in grid_cells:
src = cell.get_attribute("src")
if src.startswith("data:image"):
images.append(src)
else:
# Download and convert to base64
import requests
img_data = requests.get(src).content
b64 = base64.b64encode(img_data).decode()
images.append(f"data:image/png;base64,{b64}")
# Extract the instruction code
instruction_el = driver.find_element(By.CSS_SELECTOR, ".captcha-instruction")
instruction_code = instruction_el.text.strip()
# e.g., "664" or parsed from "Select all boxes with number 664"
import re
code_match = re.search(r'(\d{3,})', instruction_code)
instruction = code_match.group(1) if code_match else instruction_code
print(f"Instruction: {instruction}")
print(f"Images extracted: {len(images)}")
JavaScript (Puppeteer)
const puppeteer = require('puppeteer');
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://example.com/bls-protected-page');
// Extract grid images as base64
const images = await page.evaluate(() => {
const cells = document.querySelectorAll('.captcha-grid img');
return Array.from(cells).map(img => {
const canvas = document.createElement('canvas');
canvas.width = img.naturalWidth;
canvas.height = img.naturalHeight;
canvas.getContext('2d').drawImage(img, 0, 0);
return canvas.toDataURL('image/png');
});
});
// Extract instruction code
const instruction = await page.evaluate(() => {
const el = document.querySelector('.captcha-instruction');
const match = el.textContent.match(/(\d{3,})/);
return match ? match[1] : el.textContent.trim();
});
console.log(`Instruction: ${instruction}, Images: ${images.length}`);
Passo 2: envie a grade e o código para a API da CaptchaAI
O solucionador de BLS espera três coisas no corpo da requisição:
| Campo | Valor |
|---|---|
method |
bls |
instructions |
o código numérico extraído no passo 1 |
image_base64_1 … image_base64_9 |
as nove imagens da grade |
Depois de enviar a tarefa você recebe um task_id e precisa consultar res.php até a CaptchaAI devolver a lista de células.
Python
import requests
import time
import json
API_KEY = "YOUR_API_KEY"
# Prepare submission data
data = {
"key": API_KEY,
"method": "bls",
"instructions": instruction,
"json": "1",
}
# Add all 9 images
files = {}
for i, img in enumerate(images):
files[f"image_base64_{i+1}"] = (None, img)
# Submit
resp = requests.post(
"https://ocr.captchaai.com/in.php",
data=data,
files=files
).json()
if resp["status"] != 1:
raise Exception(f"Submit error: {resp['request']}")
task_id = resp["request"]
print(f"Task ID: {task_id}")
# Poll for result
for _ in range(20):
time.sleep(5)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY, "action": "get", "id": task_id, "json": "1"
}).json()
if result["status"] == 1:
solution = json.loads(result["request"])
print(f"Selected cells: {solution}") # e.g., [1, 4, 7, 8]
break
if result["request"] != "CAPCHA_NOT_READY":
raise Exception(f"Error: {result['request']}")
JavaScript
const axios = require('axios');
const FormData = require('form-data');
const form = new FormData();
form.append('key', 'YOUR_API_KEY');
form.append('method', 'bls');
form.append('instructions', instruction);
form.append('json', '1');
images.forEach((img, i) => {
form.append(`image_base64_${i + 1}`, img);
});
const submit = await axios.post('https://ocr.captchaai.com/in.php', form, {
headers: form.getHeaders(),
});
const taskId = submit.data.request;
// Poll
let solution = null;
for (let i = 0; i < 20; i++) {
await new Promise(r => setTimeout(r, 5000));
const poll = await axios.get('https://ocr.captchaai.com/res.php', {
params: { key: 'YOUR_API_KEY', action: 'get', id: taskId, json: 1 }
});
if (poll.data.status === 1) {
solution = JSON.parse(poll.data.request);
break;
}
}
console.log('Selected cells:', solution); // e.g., [2, 4, 7]
Passo 3: clique nas células que a CaptchaAI retornou
Com a lista de índices em mãos, basta localizar os elementos da grade na página e disparar o clique em cada célula indicada, na ordem em que a API retornou. Depois, envie o formulário normalmente.
# Selenium — click the cells returned by CaptchaAI
grid_cells = driver.find_elements(By.CSS_SELECTOR, ".captcha-grid .cell")
for cell_index in solution:
# cell_index is 1-based
grid_cells[cell_index - 1].click()
# Submit the form
submit_btn = driver.find_element(By.CSS_SELECTOR, ".captcha-submit")
submit_btn.click()
// Puppeteer
const cells = await page.$$('.captcha-grid .cell');
for (const idx of solution) {
await cells[idx - 1].click();
}
await page.click('.captcha-submit');
Se o clique não registrar, confira se
.captcha-grid .cellaponta para o elemento clicável (às vezes é umdivpai daimg, não a própria imagem).
Erros comuns ao resolver o CAPTCHA BLS
A maioria dos problemas com o CAPTCHA BLS vem de imagens incompletas ou do código de instrução mal extraído. A tabela abaixo cobre os casos mais comuns:
| Problema | Causa | Correção |
|---|---|---|
ERROR_BAD_PARAMETERS |
Faltam imagens ou o código de instrução não foi enviado | Confirme que as 9 imagens são data URIs base64 válidas antes de montar a requisição |
| Células erradas selecionadas | Mapeamento incorreto entre célula e índice | Verifique se a numeração segue 1 a 9, da esquerda para a direita e de cima para baixo |
| Imagens não carregam | Restrição de origem cruzada (CORS) | Baixe as imagens no servidor e converta para base64 antes de enviar |
| Código de instrução vazio | A instrução está embutida em uma imagem, não em texto | Extraia o texto normalmente ou aplique OCR na imagem da instrução |
Fluxo completo: da extração ao clique, em uma função
Reunindo os três passos acima em uma única função, você tem um fluxo reutilizável para qualquer página com esse padrão de grade — basta trocar os seletores CSS pelos da página que você está testando.
def solve_bls_captcha(driver, api_key):
"""Extract, solve, and submit a BLS CAPTCHA."""
import base64, requests, time, json, re
# 1. Extract images
grid_cells = driver.find_elements(By.CSS_SELECTOR, ".captcha-grid img")
images = []
for cell in grid_cells:
src = cell.get_attribute("src")
if src.startswith("data:image"):
images.append(src)
else:
img_data = requests.get(src).content
b64 = base64.b64encode(img_data).decode()
images.append(f"data:image/png;base64,{b64}")
# 2. Extract instruction
el = driver.find_element(By.CSS_SELECTOR, ".captcha-instruction")
match = re.search(r'(\d{3,})', el.text)
instruction = match.group(1)
# 3. Submit to CaptchaAI
data = {"key": api_key, "method": "bls", "instructions": instruction, "json": "1"}
files = {f"image_base64_{i+1}": (None, img) for i, img in enumerate(images)}
resp = requests.post("https://ocr.captchaai.com/in.php", data=data, files=files).json()
task_id = resp["request"]
# 4. Poll
for _ in range(20):
time.sleep(5)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": api_key, "action": "get", "id": task_id, "json": "1"
}).json()
if result["status"] == 1:
solution = json.loads(result["request"])
break
# 5. Click cells
clickable = driver.find_elements(By.CSS_SELECTOR, ".captcha-grid .cell")
for idx in solution:
clickable[idx - 1].click()
return solution
Perguntas frequentes
A CaptchaAI resolve o CAPTCHA BLS com que taxa de sucesso?
A CaptchaAI reporta uma alta taxa de sucesso para o CAPTCHA BLS. Como o desafio depende só da grade de imagens e do código numérico — sem áudio nem pontuação comportamental —, o resultado costuma ser consistente entre execuções.
É possível usar Playwright em vez de Selenium ou Puppeteer?
Sim. A lógica de extração — pegar as nove imagens em base64 e o texto do código de instrução — é a mesma; troque só as chamadas de DOM pelas equivalentes do Playwright. O envio para a API da CaptchaAI não muda.
O que fazer se a grade retornar menos de 9 imagens?
Confira se o seletor .captcha-grid img está capturando todas as células antes de montar a requisição — página carregada parcialmente ou lazy loading são as causas mais comuns. Enviar menos de 9 imagens gera ERROR_BAD_PARAMETERS.
Os exemplos de código existem em outras linguagens além de Python e JavaScript?
Sim, o mesmo fluxo está disponível em PHP, Go, Java, C#, Ruby, Rust, Kotlin e Bash — a lógica de extração, envio e polling é idêntica, só muda a sintaxe.
Comece a resolver CAPTCHA BLS com a CaptchaAI
Pegue sua chave de API em captchaai.com e teste o fluxo completo acima no seu ambiente — sem precisar decifrar o código de instrução manualmente.