Dans cet article, nous avons essayé de répondre à toutes les questions essentielles. Pour commencer à résoudre le problème, il faut d’abord déterminer quel système de protection est utilisé. Pour cela, vous pouvez consulter la liste des captchas et systèmes de protection antibot les plus populaires, qui présente des exemples visuels et des caractéristiques clés permettant d’identifier rapidement avec quoi vous avez affaire.
Si vous constatez que votre site utilise ComplexImage, l’étape suivante consiste à étudier plus en détail ses propriétés et son fonctionnement. Dans cet article, vous pouvez également consulter le guide d’intégration de ComplexImage afin de comprendre pleinement la façon dont il fonctionne sur votre site. Cela vous permettra non seulement de mieux connaître la protection en place, mais aussi de planifier correctement sa maintenance.
Travailler avec CapMonster Cloud via l’API comprend généralement les étapes suivantes :
type - ComplexImageTask
class - recognition
imagesBase64 - un tableau d'images au format Base64. Exemple : [“/9j/4AAQSkZJRgABAQEAAAAAAAD…”];
Task (dans les metadata) - Nom de la tâche (par exemple, dli).
https://api.capmonster.cloud/createTask{
"clientKey": "API_KEY",
"task": {
"type": "ComplexImageTask",
"class": "recognition",
"imagesBase64": [
"base64"
],
"metadata": {
"Task": "dli" // remplacez par la tâche souhaitée, la liste des modules disponibles se trouve sur https://docs.capmonster.cloud/docs/captchas/ComplexImageTask-Recognition/
}
}
}
{
"errorId":0,
"taskId":407533072
}https://api.capmonster.cloud/getTaskResult{
"clientKey":"API_KEY",
"taskId": 407533072
}
{
"solution":
{
"answer": "1",
"metadata": {
"AnswerType": "Text"
}
},
"cost": 0.0003,
"status": "ready",
"errorId": 0,
"errorCode": null,
"errorDescription": null
}
// npm install playwright @zennolab_com/capmonstercloud-client
// npx playwright install chromium
import { chromium } from 'playwright';
import { CapMonsterCloudClientFactory, ClientOptions, ComplexImageTaskRecognitionRequest } from '@zennolab_com/capmonstercloud-client';
const API_KEY = "YOUR_API_KEY";
const TARGET_URL = "https://example.com/captcha-page";
async function solveComplexImageTaskPlaywright() {
const browser = await chromium.launch({ headless: false });
const context = await browser.newContext();
const page = await context.newPage();
await page.goto(TARGET_URL);
// Localiser l'image du CAPTCHA
const captchaHandle = await page.$('#captcha'); // remplacez par le sélecteur réel
const captchaBase64 = await captchaHandle.evaluate(img => {
const canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0);
return canvas.toDataURL('image/png').split(',')[1];
});
console.log("Captcha base64:", captchaBase64.substring(0, 50) + "...");
const cmcClient = CapMonsterCloudClientFactory.Create(
new ClientOptions({ clientKey: API_KEY })
);
// Envoyer le CAPTCHA pour reconnaissance
const citRecognitionRequest = new ComplexImageTaskRecognitionRequest({
imagesBase64: [captchaBase64],
metaData: { Task: 'oocl_rotate' } // remplacez par votre type de CAPTCHA
});
const result = await cmcClient.Solve(citRecognitionRequest);
console.log("Solution received:", result);
// Traitement de la solution
const solution = result.solution;
if (!solution) {
console.error("No solution received");
return;
}
if (solution.metadata?.AnswerType === "Coordinate") {
// CAPTCHA avec coordonnées
const box = await captchaHandle.boundingBox();
for (const point of solution.answer) {
const clickX = box.x + point.X;
const clickY = box.y + point.Y;
console.log(`Clicking at: (${clickX}, ${clickY})`);
await page.mouse.click(clickX, clickY);
}
} else if (solution.metadata?.AnswerType === "Grid") {
// CAPTCHA Grid (tableau true/false)
const box = await captchaHandle.boundingBox();
const gridItems = await page.$$('#captcha_grid div'); // remplacez par les sélecteurs des éléments de la grille
const answers = solution.answer;
for (let i = 0; i < answers.length; i++) {
if (answers[i] && gridItems[i]) {
const itemBox = await gridItems[i].boundingBox();
const clickX = itemBox.x + itemBox.width / 2;
const clickY = itemBox.y + itemBox.height / 2;
console.log(`Clicking grid item ${i} at: (${clickX}, ${clickY})`);
await page.mouse.click(clickX, clickY);
}
}
} else {
console.warn("Unknown captcha solution type:", solution.metadata?.AnswerType);
}
// Cliquez sur le bouton de confirmation (si présent)
await page.click('#submit_button'); // remplacez par le sélecteur réel du bouton
console.log("Captcha solved.");
}
solveComplexImageTaskPlaywright().catch(console.error);
1. Génération du CAPTCHA sur le serveur.
2. Transmission du CAPTCHA au client
<!--CAPTCHA avec grille d'images-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Grid CAPTCHA Demo</title>
<style>
#captchaGrid {
display: grid;
grid-template-columns: repeat(3, 100px);
grid-gap: 10px;
margin-bottom: 10px;
}
.grid-item {
width: 100px;
height: 100px;
background-color: #eee;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
border: 2px solid transparent;
}
.grid-item.selected {
border-color: blue;
}
</style>
</head>
<body>
<h1>Grid CAPTCHA Demo</h1>
<div id="captchaGrid"></div>
<button id="submitBtn">Submit</button>
<button id="refreshBtn">Refresh CAPTCHA</button>
<p id="result"></p>
<script>
let captchaId;
let answers = []; // Tableau true/false pour les clics
async function loadCaptcha() {
const res = await fetch('/captcha'); // Le serveur renvoie un JSON avec captchaId et tableau d'images Base64
const data = await res.json();
captchaId = data.captchaId;
answers = new Array(data.images.length).fill(false);
const grid = document.getElementById('captchaGrid');
grid.innerHTML = '';
data.images.forEach((imgBase64, i) => {
const div = document.createElement('div');
div.className = 'grid-item';
div.style.backgroundImage = `url('data:image/png;base64,${imgBase64}')`;
div.style.backgroundSize = 'cover';
div.addEventListener('click', () => {
answers[i] = !answers[i];
div.classList.toggle('selected', answers[i]);
});
grid.appendChild(div);
});
document.getElementById('result').textContent = '';
}
document.getElementById('refreshBtn').addEventListener('click', loadCaptcha);
document.getElementById('submitBtn').addEventListener('click', async () => {
const res = await fetch('/captcha/verify', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ captchaId, answer: answers })
});
const data = await res.json();
document.getElementById('result').textContent = data.success ? 'Captcha passed!' : 'Captcha failed, try again.';
if (!data.success) loadCaptcha();
});
// Chargement du CAPTCHA au démarrage
loadCaptcha();
</script>
</body>
</html>
3. Saisie de la réponse par l'utilisateur
4. Envoi de la réponse au serveur :
5. Vérification côté serveur
<?php
session_start();
// TTL CAPTCHA en secondes
define('CAPTCHA_TTL', 300); // 5 minutes
// Génération d'image aléatoire
function generateCaptchaImage($text = null) {
$width = 100;
$height = 100;
if (!$text) {
$text = substr(str_shuffle('ABCDEFGHJKLMNPQRSTUVWXYZ23456789'), 0, 2);
}
$image = imagecreatetruecolor($width, $height);
// Fond
$bgColor = imagecolorallocate($image, rand(180, 255), rand(180, 255), rand(180, 255));
imagefilledrectangle($image, 0, 0, $width, $height, $bgColor);
// Texte
$textColor = imagecolorallocate($image, 0, 0, 0);
$fontSize = 15;
$fontFile = __DIR__ . '/Arial.ttf'; // Chemin vers la police TTF
if (file_exists($fontFile)) {
imagettftext($image, $fontSize, rand(-20,20), 10, 50, $textColor, $fontFile, $text);
} else {
imagestring($image, 5, 10, 40, $text, $textColor);
}
ob_start();
imagepng($image);
$imgData = ob_get_clean();
imagedestroy($image);
return base64_encode($imgData);
}
// Créer un CAPTCHA de type grille
function generateGridCaptcha() {
$numImages = 9; // 3x3
$images = [];
$solution = [];
for ($i = 0; $i < $numImages; $i++) {
// Résolution aléatoire, image correcte ou non (exemple)
$isCorrect = rand(0,1) === 1;
$solution[] = $isCorrect;
// Générer l'image (on peut ajouter différents objets pour un CAPTCHA réel)
$text = $isCorrect ? 'OK' : 'NO';
$images[] = generateCaptchaImage($text);
}
return ['images' => $images, 'solution' => $solution];
}
// Endpoint de génération du CAPTCHA
if ($_SERVER['REQUEST_METHOD'] === 'GET' && $_SERVER['REQUEST_URI'] === '/captcha') {
$captchaId = uniqid('captcha_', true);
$gridCaptcha = generateGridCaptcha();
$_SESSION['captchas'][$captchaId] = [
'solution' => $gridCaptcha['solution'],
'timestamp' => time()
];
header('Content-Type: application/json');
echo json_encode([
'captchaId' => $captchaId,
'images' => $gridCaptcha['images']
]);
exit;
}
// Endpoint de vérification du CAPTCHA
if ($_SERVER['REQUEST_METHOD'] === 'POST' && $_SERVER['REQUEST_URI'] === '/captcha/verify') {
$data = json_decode(file_get_contents('php://input'), true);
$captchaId = $data['captchaId'] ?? '';
$answer = $data['answer'] ?? [];
if (!isset($_SESSION['captchas'][$captchaId])) {
echo json_encode(['success' => false, 'message' => 'Captcha expired or not found']);
exit;
}
$captcha = $_SESSION['captchas'][$captchaId];
// Vérifier le TTL
if (time() - $captcha['timestamp'] > CAPTCHA_TTL) {
unset($_SESSION['captchas'][$captchaId]);
echo json_encode(['success' => false, 'message' => 'Captcha expired']);
exit;
}
// Vérifier le tableau true/false
$success = $captcha['solution'] === $answer;
// Supprimer le CAPTCHA après vérification
unset($_SESSION['captchas'][$captchaId]);
echo json_encode(['success' => $success]);
exit;
}
// 404
http_response_code(404);
echo 'Not found';
6. Étapes suivantes
En complément
Effectuez un test de charge (ex. avec k6 ou JMeter) — avec un grand nombre de requêtes :
Si vous tombez sur un site avec un CAPTCHA déjà installé ou un autre système de protection sans accès au code — pas de panique ! Il est facile d'identifier la technologie utilisée. Pour vérifier son fonctionnement, vous pouvez utiliser CapMonster Cloud dans un environnement de test isolé afin de vous assurer que le traitement des tokens et la logique fonctionnent correctement.
Pour les CAPTCHAs d'images, il suffit d'identifier le système, d'étudier son comportement et de s'assurer que la protection fonctionne. Cet article montre comment reconnaître le CAPTCHA d'images ComplexImage et comment l'intégrer ou le reconfigurer pour maintenir la protection et contrôler son fonctionnement de manière fiable.