API Tutorials

Résolvez BLS CAPTCHA avec Node.js et CaptchaAI

Le CAPTCHA BLS ne se traite pas comme un reCAPTCHA : il n'y a aucun token à injecter dans un champ caché. Vous envoyez neuf images et un code d'instruction à l'API CaptchaAI, vous recevez une liste de numéros de cellules, et c'est votre script Node.js qui clique lui-même sur les bonnes vignettes. Ce tutoriel déroule ce workflow de bout en bout avec Puppeteer et axios.


Ce que l'API renvoie réellement

Retenez cette différence avant d'écrire la moindre ligne : sur un défi en grille, la réponse de l'API est un tableau d'indices, du type [1, 4, 7, 8]. Aucun g-recaptcha-response, aucun champ de formulaire à remplir. Trois conséquences pratiques :

  • votre navigateur doit rester ouvert sur la même page entre l'envoi et la réponse, puisque vous devrez cliquer dans la grille d'origine ;
  • les neuf images doivent partir ensemble, dans l'ordre d'affichage, sans quoi les indices retournés ne correspondront à rien ;
  • le code d'instruction compte autant que les images : c'est lui qui dit quoi sélectionner.

Ce qu'il vous faut avant de commencer

Élément Valeur
Clé API CaptchaAI Depuis captchaai.com
Node.js 14+
Bibliothèque axios (npm install axios)

Un compte BASIC ($15/mois, 5 threads) suffit largement pour développer et tester : la facturation CaptchaAI se fait par thread simultané, avec un nombre de résolutions illimité sur le mois. Les tarifs sont en dollars US.


La grille BLS 3×3 et le code d'instruction

La grille est numérotée de gauche à droite, puis de haut en bas :

1 | 2 | 3
---------
4 | 5 | 6
---------
7 | 8 | 9

Un code numérique — par exemple « 664 » — indique les vignettes à sélectionner. CaptchaAI renvoie les indices des cellules correspondantes, que vous n'avez plus qu'à rejouer côté navigateur.


Étape 1 : extraire les 9 images de la grille BLS

Ouvrez la page, lisez le code d'instruction, puis récupérez les neuf sources d'images. Certaines vignettes BLS sont déjà servies en data: ; les autres doivent être téléchargées puis converties en base64. Le tableau images doit rester dans l'ordre d'affichage de la grille.

const axios = require('axios');
const puppeteer = require('puppeteer');

const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://example.com/bls-form');

// Get instruction code
const instruction = await page.$eval('.bls-instruction', (el) => el.textContent.trim());

// Get all 9 cell image URLs and convert to base64
const cellImages = await page.$$eval('.bls-grid img', (imgs) =>
  imgs.map((img) => img.src)
);

const images = [];
for (const src of cellImages) {
  if (src.startsWith('data:')) {
    images.push(src);
  } else {
    const { data } = await axios.get(src, { responseType: 'arraybuffer' });
    const b64 = Buffer.from(data).toString('base64');
    images.push(`data:image/png;base64,${b64}`);
  }
}

Étape 2 : envoyer la grille à l'API CaptchaAI

L'envoi se fait en POST sur in.php, avec method=bls, le code d'instruction et les neuf images numérotées de image_base64_1 à image_base64_9. Gardez YOUR_API_KEY hors du dépôt : une variable d'environnement ou un fichier de secrets, jamais une valeur en dur poussée sur GitHub.

const API_KEY = 'YOUR_API_KEY';
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));

const params = new URLSearchParams({
  key: API_KEY,
  method: 'bls',
  instructions: instruction,
  json: '1',
});

// Add all 9 images
images.forEach((img, i) => {
  params.append(`image_base64_${i + 1}`, img);
});

const { data: submitData } = await axios.post(
  'https://ocr.captchaai.com/in.php',
  params.toString()
);

if (submitData.status !== 1) throw new Error(submitData.request);
const taskId = submitData.request;
console.log(`Task submitted: ${taskId}`);

Si status ne vaut pas 1, le champ request contient le code d'erreur. Traitez-le tout de suite plutôt que d'enchaîner sur le polling.


Étape 3 : interroger le résultat

L'API travaille en asynchrone. Vous patientez quelques secondes, puis vous interrogez res.php jusqu'à obtenir la réponse. Tant que la tâche est en cours, le service répond CAPCHA_NOT_READY ; toute autre valeur est une vraie erreur et doit interrompre la boucle.

await sleep(5000);

let selectedCells;
for (let i = 0; i < 30; i++) {
  const { data: pollData } = await axios.get('https://ocr.captchaai.com/res.php', {
    params: { key: API_KEY, action: 'get', id: taskId, json: 1 },
  });

  if (pollData.status === 1) {
    selectedCells = JSON.parse(pollData.request);
    console.log('Selected cells:', selectedCells);
    break;
  }
  if (pollData.request !== 'CAPCHA_NOT_READY') {
    throw new Error(pollData.request);
  }
  await sleep(5000);
}

Un intervalle de 5 secondes est un bon compromis : plus court, vous multipliez les requêtes inutiles ; plus long, vous laissez dormir un résultat déjà prêt, car une grille BLS est traitée en moins d'une seconde côté CaptchaAI. Le reste du délai vient de l'upload des neuf images et de la file d'attente.


Étape 4 : cliquer sur les cellules retournées

Les indices reçus commencent à 1, alors que le tableau d'éléments renvoyé par Puppeteer commence à 0 : d'où le cellNum - 1. Cliquez chaque cellule, puis soumettez le formulaire.

// Click each identified cell
const gridCells = await page.$$('.bls-grid img');
for (const cellNum of selectedCells) {
  await gridCells[cellNum - 1].click();
}

// Submit the form
await page.click('.bls-submit');
console.log(`Solved: clicked cells ${JSON.stringify(selectedCells)}`);
await browser.close();

Résultat attendu :

Selected cells: [1, 4, 7, 8]
Solved: clicked cells [1,4,7,8]

Un scénario concret : vérifier votre propre parcours de rendez-vous

Le cas d'usage le plus fréquent chez les lecteurs francophones, en France comme au Maghreb, ce sont les portails de rendez-vous BLS. Le cadre à respecter est simple : n'automatisez que votre propre démarche, sur un compte et un environnement dont vous êtes responsable, et gardez le rythme d'une navigation humaine. Un script qui recharge une page toutes les secondes n'est ni utile ni acceptable.

Côté conformité, la logique RGPD s'applique dès que vous manipulez un dossier : ne conservez pas les vignettes téléchargées plus longtemps que nécessaire, ne journalisez aucune donnée personnelle dans vos logs de debug, et purgez le dossier de travail en fin d'exécution. Un simple nettoyage du répertoire temporaire après la soumission évite de laisser traîner des captures de formulaire sur un serveur OVHcloud ou Scaleway.

Pour la montée en charge, raisonnez en threads plutôt qu'en nombre de résolutions : un thread correspond à un défi en cours de traitement. Cinq formulaires traités en parallèle demandent cinq threads, donc le plan BASIC ; au-delà, STANDARD ($30/mois, 15 threads) puis ADVANCE ($90/mois, 50 threads) prennent le relais. Chaque instance Puppeteer consommant sa part de mémoire, c'est d'ailleurs souvent votre machine, et non votre plan, qui plafonne en premier.


Erreurs courantes et correctifs

Erreur Cause Correctif
ERROR_BAD_PARAMETERS Images ou code d'instruction manquants Envoyez les 9 images et le code d'instruction dans la même requête
CAPCHA_NOT_READY Tâche encore en traitement Continuez à interroger res.php toutes les 5 secondes
ERROR_ZERO_BALANCE Solde épuisé Rechargez votre compte CaptchaAI
Indices décalés d'un cran Conversion 1→0 oubliée Cliquez sur gridCells[cellNum - 1]
Clics sans effet La grille a été régénérée entre-temps Relancez l'extraction et envoyez une nouvelle tâche

FAQ

Le CAPTCHA BLS renvoie-t-il un token comme reCAPTCHA v2 ?

Non. La réponse est une liste d'indices de cellules, par exemple [1, 4, 7, 8]. C'est votre script qui reproduit les clics dans le navigateur ; il n'y a aucun champ de token à remplir.

Combien de threads faut-il pour traiter plusieurs formulaires en parallèle ?

Un thread par défi simultané. Le plan BASIC ($15/mois, 5 threads) couvre cinq navigateurs en parallèle, avec un nombre de résolutions illimité ; passez à STANDARD ($30/mois, 15 threads) seulement si vous saturez réellement vos threads.

Que faire si la boucle d'interrogation expire sans réponse ?

Abandonnez la tâche et repartez de l'étape 1 avec une grille fraîche. Les images BLS ont une durée de vie courte : réutiliser un ancien taskId sur une grille rechargée ferait cliquer votre script au mauvais endroit.

CaptchaAI prend-il en charge hCaptcha sur le même compte ?

Non — hCaptcha et FunCaptcha (Arkose Labs) ne sont pas pris en charge. Le compte couvre notamment BLS, les grilles d'images, l'OCR, reCAPTCHA v2 et v3, Cloudflare Turnstile et Challenge, GeeTest v3, ainsi que CaptchaFox (bêta), Friendly Captcha (bêta) et Lemin (bêta).


Guides associés


Créez votre compte et résolvez votre première grille BLS →

Les commentaires sont désactivés pour cet article.