Casos de Uso

Resolver CAPTCHA en sitios web japoneses y coreanos

¿Tu script de scraping o tu suite de QA se topa con un CAPTCHA de imagen lleno de caracteres japoneses o coreanos y devuelve texto vacío? La causa casi siempre es la misma: el OCR pensado para el alfabeto latino no reconoce hiragana, katakana, kanji ni hangul. La solución es enviar la imagen al OCR de CaptchaAI con el parámetro language=2, que activa los modelos entrenados en caracteres CJK (chino, japonés y coreano). Con ese único ajuste, la misma llamada a la API que ya usas para un CAPTCHA de texto normal empieza a devolver los caracteres correctos.

Es un obstáculo frecuente para las agencias y los freelancers de habla hispana que monitorizan precios en marketplaces japoneses, comprueban disponibilidad en portales coreanos o hacen QA de formularios de registro en Asia oriental. Esta guía muestra cómo resolver estos CAPTCHA con Python y JavaScript, qué sistemas de escritura vas a encontrar y cómo evitar los dos errores que más rompen los resultados: el idioma mal configurado y la codificación de caracteres.

Tipos de CAPTCHA que verás en Japón y Corea

No todos los sitios usan el mismo desafío. Antes de escribir una línea de código conviene identificar qué tipo tienes delante, porque eso decide qué solver de CaptchaAI necesitas.

Región Tipos habituales en los sitios Conjuntos de caracteres Solver de CaptchaAI
Japón Imagen con hiragana/katakana, reCAPTCHA v2/v3 Hiragana, katakana, kanji, latín Image/OCR, reCAPTCHA
Corea Imagen con hangul, reCAPTCHA, deslizadores propietarios Hangul, latín Image/OCR, reCAPTCHA
Ambos reCAPTCHA v2/v3 (interfaz localizada) N/D (basado en token) reCAPTCHA

Un apunte de honestidad: algunos sitios japoneses despliegan hCaptcha, y CaptchaAI no resuelve hCaptcha por ahora. Para los CAPTCHA de imagen y para reCAPTCHA v2/v3 sí tienes cobertura directa; para hCaptcha necesitarás otra estrategia. La interfaz del sitio puede estar en japonés o coreano, pero eso no cambia nada: un reCAPTCHA sigue siendo un desafío basado en token e independiente del idioma.

Python: resolver un CAPTCHA de imagen japonés

El patrón es el de siempre: descargas o lees la imagen, la codificas en base64, la envías al endpoint in.php y sondeas res.php hasta que el resultado está listo. La clave está en el campo language=2. Estas funciones cubren japonés, coreano y el caso en el que el CAPTCHA vive dentro de una sesión autenticada.

import requests
import base64
import time

API_KEY = "YOUR_API_KEY"
SUBMIT_URL = "https://ocr.captchaai.com/in.php"
RESULT_URL = "https://ocr.captchaai.com/res.php"


def solve_japanese_captcha(image_path: str) -> str:
    """Solve a Japanese character image CAPTCHA."""
    with open(image_path, "rb") as f:
        image_b64 = base64.b64encode(f.read()).decode()

    resp = requests.post(SUBMIT_URL, data={
        "key": API_KEY,
        "method": "base64",
        "body": image_b64,
        "language": 2,          # CJK character support
        "json": 1,
    }, timeout=30).json()

    if resp.get("status") != 1:
        raise RuntimeError(f"Submit: {resp.get('request')}")

    task_id = resp["request"]
    for _ in range(24):
        time.sleep(5)
        poll = requests.get(RESULT_URL, params={
            "key": API_KEY, "action": "get", "id": task_id, "json": 1,
        }, timeout=15).json()

        if poll.get("request") == "CAPCHA_NOT_READY":
            continue
        if poll.get("status") == 1:
            return poll["request"]
        raise RuntimeError(f"Solve: {poll.get('request')}")

    raise RuntimeError("Timeout")


def solve_korean_captcha(image_path: str) -> str:
    """Solve a Korean hangul image CAPTCHA."""
    with open(image_path, "rb") as f:
        image_b64 = base64.b64encode(f.read()).decode()

    resp = requests.post(SUBMIT_URL, data={
        "key": API_KEY,
        "method": "base64",
        "body": image_b64,
        "language": 2,
        "json": 1,
    }, timeout=30).json()

    if resp.get("status") != 1:
        raise RuntimeError(f"Submit: {resp.get('request')}")

    task_id = resp["request"]
    for _ in range(24):
        time.sleep(5)
        poll = requests.get(RESULT_URL, params={
            "key": API_KEY, "action": "get", "id": task_id, "json": 1,
        }, timeout=15).json()

        if poll.get("request") == "CAPCHA_NOT_READY":
            continue
        if poll.get("status") == 1:
            return poll["request"]
        raise RuntimeError(f"Solve: {poll.get('request')}")

    raise RuntimeError("Timeout")


def solve_captcha_from_session(session: requests.Session,
                                captcha_url: str,
                                language: int = 2) -> str:
    """Download and solve a CAPTCHA within a session context."""
    resp = session.get(captcha_url, timeout=15)
    image_b64 = base64.b64encode(resp.content).decode()

    submit = requests.post(SUBMIT_URL, data={
        "key": API_KEY,
        "method": "base64",
        "body": image_b64,
        "language": str(language),
        "json": 1,
    }, timeout=30).json()

    if submit.get("status") != 1:
        raise RuntimeError(f"Submit: {submit.get('request')}")

    task_id = submit["request"]
    for _ in range(24):
        time.sleep(5)
        poll = requests.get(RESULT_URL, params={
            "key": API_KEY, "action": "get", "id": task_id, "json": 1,
        }, timeout=15).json()

        if poll.get("request") == "CAPCHA_NOT_READY":
            continue
        if poll.get("status") == 1:
            return poll["request"]
        raise RuntimeError(f"Solve: {poll.get('request')}")

    raise RuntimeError("Timeout")


# --- Usage ---

# Japanese CAPTCHA
jp_text = solve_japanese_captcha("japanese_captcha.png")
print(f"Japanese CAPTCHA: {jp_text}")

# Korean CAPTCHA from a live session
session = requests.Session()
session.headers["Accept-Language"] = "ko-KR,ko;q=0.9"
session.get("https://example.kr/login")  # establish session
kr_text = solve_captcha_from_session(session, "https://example.kr/captcha/image")
print(f"Korean CAPTCHA: {kr_text}")

La función solve_captcha_from_session es la más útil en la práctica: muchos CAPTCHA japoneses y coreanos solo se generan tras iniciar una sesión, así que descargar la imagen con las mismas cookies del navegador evita que el token quede huérfano.

JavaScript: resolver CAPTCHA japoneses y coreanos

Si tu pipeline vive en Node.js, el flujo es idéntico. solveAsianCaptcha trabaja sobre un archivo local y solveFromUrl descarga la imagen directamente de la página, ajustando el encabezado Accept-Language al idioma de destino.

const API_KEY = "YOUR_API_KEY";
const SUBMIT_URL = "https://ocr.captchaai.com/in.php";
const RESULT_URL = "https://ocr.captchaai.com/res.php";
const fs = require("fs");

async function solveAsianCaptcha(imagePath) {
  const imageB64 = fs.readFileSync(imagePath, "base64");

  const body = new URLSearchParams({
    key: API_KEY,
    method: "base64",
    body: imageB64,
    language: "2",
    json: "1",
  });

  const resp = await (await fetch(SUBMIT_URL, { method: "POST", body })).json();
  if (resp.status !== 1) throw new Error(`Submit: ${resp.request}`);

  const taskId = resp.request;
  for (let i = 0; i < 24; i++) {
    await new Promise((r) => setTimeout(r, 5000));
    const url = `${RESULT_URL}?key=${API_KEY}&action=get&id=${taskId}&json=1`;
    const poll = await (await fetch(url)).json();
    if (poll.request === "CAPCHA_NOT_READY") continue;
    if (poll.status === 1) return poll.request;
    throw new Error(`Solve: ${poll.request}`);
  }
  throw new Error("Timeout");
}

async function solveFromUrl(captchaUrl, cookies = "") {
  const resp = await fetch(captchaUrl, {
    headers: { Cookie: cookies, "Accept-Language": "ja-JP,ja;q=0.9" },
  });
  const buffer = await resp.arrayBuffer();
  const imageB64 = Buffer.from(buffer).toString("base64");

  const body = new URLSearchParams({
    key: API_KEY, method: "base64", body: imageB64,
    language: "2", json: "1",
  });

  const submitResp = await (await fetch(SUBMIT_URL, { method: "POST", body })).json();
  if (submitResp.status !== 1) throw new Error(`Submit: ${submitResp.request}`);

  const taskId = submitResp.request;
  for (let i = 0; i < 24; i++) {
    await new Promise((r) => setTimeout(r, 5000));
    const url = `${RESULT_URL}?key=${API_KEY}&action=get&id=${taskId}&json=1`;
    const poll = await (await fetch(url)).json();
    if (poll.request === "CAPCHA_NOT_READY") continue;
    if (poll.status === 1) return poll.request;
    throw new Error(`Solve: ${poll.request}`);
  }
  throw new Error("Timeout");
}

// Usage
const jpText = await solveAsianCaptcha("japanese_captcha.png");
console.log(`Japanese: ${jpText}`);

Los sistemas de escritura que debes reconocer

Saber qué escritura tienes delante te ayuda a interpretar los resultados y a diagnosticar fallos. El japonés combina hasta tres sistemas en una sola pantalla; el coreano usa uno solo, pero con miles de bloques silábicos posibles.

Sistema de escritura Caracteres Notas
Hiragana 46 caracteres básicos Silabario fonético para palabras japonesas nativas
Katakana 46 caracteres básicos Silabario fonético para préstamos extranjeros
Kanji Miles de caracteres Ideogramas compartidos con el chino; los CAPTCHA usan un subconjunto común
Hangul 24 letras básicas, ~11.000 bloques silábicos Alfabeto fonético coreano
Mixto (japonés) Hiragana + katakana + kanji + latín El caso más difícil: varios sistemas en una sola imagen

Costo y volumen: qué plan necesitas

Los CAPTCHA de imagen CJK se facturan igual que cualquier otro tipo: CaptchaAI cobra por thread concurrente, no por resolución, y cada plan incluye resoluciones ilimitadas por thread durante el mes. Para validar un flujo puntual o hacer scraping ligero, el plan BASIC ($15/mes, 5 threads) resuelve cinco imágenes en paralelo. Para una operación continua que recorre varios sitios japoneses y coreanos a la vez, ADVANCE ($90/mes, 50 threads) o PREMIUM ($170/mes, 100 threads) dan margen sin sumar tarifas por solicitud. Como es un costo mensual fijo en USD, resulta predecible frente al pago por resolución, algo que agradecen las agencias que facturan en monedas locales volátiles. El tipo de carácter no encarece nada: un kanji cuesta lo mismo que una letra latina.

Solución de problemas frecuentes

Problema Causa Solución
Hiragana confundido con katakana Apariencia muy parecida entre ciertos pares de caracteres Usa language=2 para CJK: CaptchaAI los diferencia
Caracteres hangul corruptos (mojibake) La respuesta se decodifica como Latin-1 Fuerza UTF-8: response.encoding = 'utf-8'
Falla con escritura mixta en una imagen Varios conjuntos de caracteres a la vez CaptchaAI procesa scripts mixtos con language=2
Baja precisión en texto muy estilizado Distorsión fuerte sobre los caracteres Envía imágenes de mayor resolución
La sesión caduca tras resolver El tiempo de resolución de caracteres complejos es largo Prepara la sesión, resuelve y envía de inmediato

Preguntas frecuentes

¿Qué plan de CaptchaAI me conviene para procesar CAPTCHA japoneses y coreanos en volumen?

Depende de cuántas imágenes resuelvas en paralelo. Como CaptchaAI cobra por thread concurrente con resoluciones ilimitadas, el plan BASIC ($15/mes, 5 threads) basta para pruebas y scraping ligero, mientras que ADVANCE ($90/mes, 50 threads) cubre operaciones continuas sobre varios sitios a la vez. El sistema de escritura no cambia el precio.

¿Por qué el texto hangul me llega con caracteres corruptos?

Casi siempre es un problema de codificación, no de resolución. Si tu cliente HTTP decodifica la respuesta como Latin-1, los caracteres coreanos se rompen. Fuerza UTF-8 (response.encoding = 'utf-8' en Python) antes de leer el resultado y volverán a mostrarse correctamente.

¿Puedo usar CaptchaAI si un sitio japonés muestra hCaptcha?

No. CaptchaAI no resuelve hCaptcha por ahora. Sí resuelve los CAPTCHA de imagen (con language=2), reCAPTCHA v2/v3 y Cloudflare Turnstile, que también verás en sitios de Japón y Corea. Para un formulario protegido con hCaptcha necesitarás otra vía.

¿Necesito un proxy con IP japonesa o coreana para que funcione la resolución?

No para la resolución en sí: envías la imagen a la API y recibes el texto sin importar tu ubicación. El proxy solo entra en juego si el sitio de destino bloquea tu región; en ese caso usa una salida de red autorizada y define los encabezados Accept-Language correctos (ja-JP o ko-KR).

Artículos relacionados

  • Resolver CAPTCHA en sitios web chinos

Próximos pasos

Empieza a resolver CAPTCHA japoneses y coreanos hoy mismo: consigue tu API key de CaptchaAI, añade language=2 a tu llamada y procesa cualquier carácter CJK.

Guías relacionadas:

Los comentarios están deshabilitados para este artículo.