Precios de la solución ComplexImage
| CAPTCHA | Precio (USD) |
|---|---|
$ 0.30 1000 respuestas |
En este artículo hemos intentado responder a todas las preguntas clave. Para empezar a resolver la tarea, primero hay que determinar qué sistema de protección se está utilizando. Para ello, puedes consultar la lista de captchas y sistemas de protección antibot más populares, donde se muestran ejemplos visuales y señales clave que te ayudarán a identificar rápidamente con qué estás tratando.
Si descubres que tu sitio web utiliza ComplexImage, el siguiente paso será analizar con más detalle sus propiedades y su funcionamiento. En este mismo artículo también puedes consultar la guía de integración de ComplexImage para comprender por completo cómo funciona en tu sitio. Esto te permitirá no solo entender la protección actual, sino también planificar correctamente su mantenimiento.
Cómo resolver un CAPTCHA de imágenes usando CapMonster Cloud
- Abra la página con el formulario y asegúrese de que el CAPTCHA se muestre.
- Intente enviar el formulario sin resolver el CAPTCHA: el servidor debería devolver un error.
- Después de resolver correctamente el CAPTCHA, el formulario debería enviarse sin errores.
Trabajar con CapMonster Cloud mediante la API suele implicar los siguientes pasos:
type - ComplexImageTask
class - recognition
imagesBase64 - un array de imágenes en formato Base64. Ejemplo: [“/9j/4AAQSkZJRgABAQEAAAAAAAD…”];
Task (dentro de metadata) - Nombre de la tarea (por ejemplo, dli).
https://api.capmonster.cloud/createTask{
"clientKey": "API_KEY",
"task": {
"type": "ComplexImageTask",
"class": "recognition",
"imagesBase64": [
"base64"
],
"metadata": {
"Task": "dli" // reemplace con la tarea deseada, la lista de módulos disponibles se encuentra en 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);
// Localizar la imagen del CAPTCHA
const captchaHandle = await page.$('#captcha'); // reemplace con el selector real
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 })
);
// Enviar CAPTCHA para reconocimiento
const citRecognitionRequest = new ComplexImageTaskRecognitionRequest({
imagesBase64: [captchaBase64],
metaData: { Task: 'oocl_rotate' } // reemplace con su tipo de CAPTCHA
});
const result = await cmcClient.Solve(citRecognitionRequest);
console.log("Solution received:", result);
// Procesar la solución
const solution = result.solution;
if (!solution) {
console.error("No solution received");
return;
}
if (solution.metadata?.AnswerType === "Coordinate") {
// CAPTCHA con coordenadas
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 de cuadrícula (array true/false)
const box = await captchaHandle.boundingBox();
const gridItems = await page.$$('#captcha_grid div'); // reemplace con los selectores de los elementos de la cuadrícula
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);
}
// Hacer clic en el botón de confirmación (si lo hay)
await page.click('#submit_button'); // reemplace con el selector real del botón
console.log("Captcha solved.");
}
solveComplexImageTaskPlaywright().catch(console.error);
1. Generación de CAPTCHA en el servidor.
- Se crea una imagen CAPTCHA: una imagen o cuadrícula de imágenes.
- Se añaden ruido, distorsiones y elementos aleatorios para proteger contra bots.
- Se genera un captchaId único y se almacena la solución correcta (en memoria, base de datos o caché).
2. Enviar CAPTCHA al cliente
- El servidor envía al cliente captchaId y la imagen (Base64 o URL).
- El cliente muestra el CAPTCHA, por ejemplo con <img> o cuadrícula <div> con instrucciones.
<!--CAPTCHA de cuadrícula de imágenes-->
<!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 = []; // Array true/false para clics
async function loadCaptcha() {
const res = await fetch('/captcha'); // El servidor devuelve JSON con captchaId y array de imágenes 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();
});
// Cargar CAPTCHA al iniciar
loadCaptcha();
</script>
</body>
</html>
3. Ingreso de la respuesta por el usuario
- El usuario ingresa texto, hace clic en imágenes o rota objetos.
- El cliente forma la respuesta en la estructura adecuada:
- CAPTCHA de texto → cadena
- Cuadrícula → array true/false
- Coordenadas → array de {X, Y}
4. Enviar respuesta al servidor:
- El cliente envía POST con captchaId y respuesta (answer).
- Opcionalmente, se puede enviar token de sesión para evitar repetición.
5. Verificación en el servidor
- El servidor busca la sesión de CAPTCHA por captchaId.
- Compara la respuesta del usuario con la solución correcta.
- Devuelve success: true/false.
- Si falla, se puede actualizar el CAPTCHA.
<?php
session_start();
// TTL de CAPTCHA en segundos
define('CAPTCHA_TTL', 300); // 5 minutos
// Generar imagen aleatoria
function generateCaptchaImage($text = null) {
$width = 100;
$height = 100;
if (!$text) {
$text = substr(str_shuffle('ABCDEFGHJKLMNPQRSTUVWXYZ23456789'), 0, 2);
}
$image = imagecreatetruecolor($width, $height);
// Fondo
$bgColor = imagecolorallocate($image, rand(180, 255), rand(180, 255), rand(180, 255));
imagefilledrectangle($image, 0, 0, $width, $height, $bgColor);
// Texto
$textColor = imagecolorallocate($image, 0, 0, 0);
$fontSize = 15;
$fontFile = __DIR__ . '/Arial.ttf'; // Ruta a fuente 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);
}
// Crear CAPTCHA de cuadrícula
function generateGridCaptcha() {
$numImages = 9; // 3x3
$images = [];
$solution = [];
for ($i = 0; $i < $numImages; $i++) {
// Solución aleatoria, imagen correcta o no (ejemplo)
$isCorrect = rand(0,1) === 1;
$solution[] = $isCorrect;
// Generar imagen (se pueden agregar diferentes objetos para CAPTCHA real)
$text = $isCorrect ? 'OK' : 'NO';
$images[] = generateCaptchaImage($text);
}
return ['images' => $images, 'solution' => $solution];
}
// Endpoint de generación de 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 verificación de 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];
// Verificar TTL
if (time() - $captcha['timestamp'] > CAPTCHA_TTL) {
unset($_SESSION['captchas'][$captchaId]);
echo json_encode(['success' => false, 'message' => 'Captcha expired']);
exit;
}
// Verificar array true/false
$success = $captcha['solution'] === $answer;
// Eliminar CAPTCHA después de la verificación
unset($_SESSION['captchas'][$captchaId]);
echo json_encode(['success' => $success]);
exit;
}
// 404
http_response_code(404);
echo 'Not found';
6. Pasos siguientes
- CAPTCHA exitosa → se permite el proceso protegido (formulario, registro, etc.).
- CAPTCHA fallida → se emite una nueva, opcionalmente limitando los intentos.
Adicionalmente
- Use TTL (tiempo de vida) para las sesiones de CAPTCHA, para que expiren automáticamente.
- Cache imágenes y use URLs temporales para ahorrar recursos.
- Asegure el correcto funcionamiento de clics y toques en dispositivos móviles.
- Lleve registros y análisis para mejorar la experiencia del usuario y la protección contra bots.
Realice pruebas de carga (p. ej., con k6 o JMeter) — con muchas solicitudes:
- las imágenes deben generarse correctamente;
- el servidor no debe mezclar respuestas de usuarios;
- la verificación de clics debe permanecer estable.
Captchas compatibles
Si encuentra un sitio con CAPTCHA ya instalado u otro sistema de protección y no tiene acceso al código — ¡no hay problema! Es fácil identificar la tecnología utilizada. Para verificar el funcionamiento, puede usar CapMonster Cloud en un entorno de prueba aislado y asegurarse de que el procesamiento de tokens y la lógica funcionen correctamente.
Con CAPTCHA de imágenes basta con identificar el sistema, estudiar su comportamiento y asegurarse de que la protección funcione. En este artículo mostramos cómo reconocer CAPTCHA de imágenes (ComplexImage) y cómo integrarla o reconfigurarla para mantener la protección y controlarla de manera confiable.