Hướng Dẫn API

Cách mã hóa Base64 ảnh CAPTCHA chuẩn cho CaptchaAI API

Gửi sai định dạng base64 là lý do phổ biến nhất khiến CaptchaAI trả về ERROR_WRONG_FILE_EXTENSION — hoặc tệ hơn, trả kết quả sai mà không báo lỗi. Vấn đề thường không phải CaptchaAI đọc nhầm ảnh, mà là cách bạn mã hóa trước khi gửi: dính tiền tố data:image/png;base64,, mã hóa hai lần, hoặc đọc file ở chế độ text thay vì binary.

Bài này đi thẳng vào cách mã hóa đúng, theo bốn lát cắt — ví dụ dùng Python, chạy được ngay:

  • Gửi ảnh qua tham số method=base64
  • Lấy base64 từ file, từ URL và từ ảnh chụp Selenium
  • Tránh ba lỗi mã hóa phổ biến nhất
  • Validate ảnh trước khi gửi thay vì đợi API trả lỗi

Chuẩn gửi ảnh CAPTCHA qua tham số method=base64

CaptchaAI nhận CAPTCHA hình ảnh dưới dạng base64 qua endpoint in.php, với tham số method=base64 và nội dung ảnh đặt trong trường body. Không cần header đặc biệt — chỉ một request POST thông thường — nhưng chuỗi base64 gửi lên phải thuần: không tiền tố, không xuống dòng, không escape ký tự.

import requests
import base64
import os

def submit_image_captcha(image_base64):
    """Submit base64-encoded image to CaptchaAI."""
    resp = requests.post("https://ocr.captchaai.com/in.php", data={
        "key": os.environ["CAPTCHAAI_API_KEY"],
        "method": "base64",
        "body": image_base64,
        "json": 1,
    }, timeout=30)
    return resp.json()

Ba cách lấy chuỗi base64: file, URL, ảnh chụp Selenium

Từ file cục bộ

Cách đơn giản nhất: đọc file ảnh CAPTCHA đã lưu rồi mã hóa bằng module base64 có sẵn. Luôn mở file ở chế độ "rb" — mở nhầm "r" chính là Sai lầm 3 ở dưới.

# from_file.py
import base64

def encode_from_file(filepath):
    """Read an image file and return base64 string."""
    with open(filepath, "rb") as f:
        raw = f.read()
    return base64.b64encode(raw).decode("ascii")

# Usage
b64 = encode_from_file("captcha.png")
print(f"Encoded length: {len(b64)} chars")

Từ URL

Khi CAPTCHA có URL ảnh riêng — thường gặp trên trang đăng ký hoặc cổng tra cứu — tải bằng requests.get() rồi mã hóa nội dung phản hồi. Luôn kiểm tra Content-Type trước: server trả trang HTML lỗi thay vì ảnh (session hết hạn, sai URL) sẽ khiến bạn mã hóa nhầm cả trang HTML, và CaptchaAI báo lỗi định dạng ngay.

# from_url.py
import requests
import base64

def encode_from_url(image_url):
    """Download image and return base64 string."""
    resp = requests.get(image_url, timeout=15)
    resp.raise_for_status()

    # Verify it's actually an image
    content_type = resp.headers.get("Content-Type", "")
    if not content_type.startswith("image/"):
        raise ValueError(f"Not an image: {content_type}")

    return base64.b64encode(resp.content).decode("ascii")

# Usage
b64 = encode_from_url("https://example.com/captcha.png")

Từ ảnh chụp Selenium

Khi CAPTCHA không có URL ảnh riêng mà chỉ hiển thị trong một phần tử <canvas> hoặc <img> render động, chụp trực tiếp phần tử đó là cách ổn định nhất. Selenium có sẵn element.screenshot_as_base64, trả ngay chuỗi base64 — không cần tự mã hóa lại.

Một đội QA outsourcing tại TP.HCM theo dõi giá trên Shopee và Tiki bằng pipeline Selenium từng dính đúng lỗi này: ảnh lấy qua screenshot_as_base64 bị mã hóa thêm một lần nữa, khiến cả batch báo ERROR_WRONG_FILE_EXTENSION dù ảnh gốc hợp lệ. Cần crop một vùng cụ thể thì dùng encode_from_page_crop() để chụp toàn trang rồi cắt theo tọa độ.

# from_selenium.py
import base64
from selenium.webdriver.common.by import By

def encode_from_element(driver, selector):
    """Screenshot a specific element and return base64."""
    element = driver.find_element(By.CSS_SELECTOR, selector)
    screenshot_b64 = element.screenshot_as_base64
    return screenshot_b64

def encode_from_page_crop(driver, selector):
    """Crop a specific region from the page screenshot."""
    from PIL import Image
    import io

    element = driver.find_element(By.CSS_SELECTOR, selector)
    location = element.location
    size = element.size

    # Full page screenshot
    png = driver.get_screenshot_as_png()
    img = Image.open(io.BytesIO(png))

    # Crop to element bounds
    left = location["x"]
    top = location["y"]
    right = left + size["width"]
    bottom = top + size["height"]
    cropped = img.crop((left, top, right, bottom))

    # Encode
    buffer = io.BytesIO()
    cropped.save(buffer, format="PNG")
    return base64.b64encode(buffer.getvalue()).decode("ascii")

Ba lỗi mã hóa base64 hay gặp nhất

Phần lớn lỗi giải sai không đến từ CaptchaAI mà từ chuỗi base64 bạn gửi lên:

  • Còn dính tiền tố data:image/...;base64,
  • Mã hóa hai lần một chuỗi vốn đã là base64
  • Đọc file ảnh ở chế độ text thay vì binary

Sai lầm 1: Giữ nguyên tiền tố data URI

Trình duyệt và một số thư viện chụp ảnh trả về base64 kèm tiền tố data:image/png;base64,. CaptchaAI chỉ cần phần base64 thuần sau dấu phẩy — gửi nguyên tiền tố bị coi là dữ liệu không hợp lệ.

# WRONG — includes data URI prefix
bad = "data:image/png;base64,iVBORw0KGgo..."

# RIGHT — raw base64 only
good = "iVBORw0KGgo..."

# Fix: Strip the prefix
def clean_base64(b64_string):
    if "," in b64_string:
        return b64_string.split(",", 1)[1]
    return b64_string

Sai lầm 2: Mã hóa hai lần

Đây là lỗi đội QA ở trên gặp phải: screenshot_as_base64 của Selenium đã trả về base64 sẵn. Gọi thêm base64.b64encode() tạo ra chuỗi base64-của-base64 mà CaptchaAI không decode được.

# WRONG — encoding an already-encoded string
already_b64 = element.screenshot_as_base64
double_encoded = base64.b64encode(already_b64.encode()).decode()  # BAD

# RIGHT — use as-is
correct = element.screenshot_as_base64  # Already base64

Sai lầm 3: Mã hóa văn bản thay vì byte

Mở file bằng "r" thay vì "rb" khiến Python cố decode dữ liệu nhị phân thành text, làm hỏng byte gốc trước khi mã hóa. Kết quả: ảnh mã hóa xong không khớp ảnh gốc, CaptchaAI sẽ giải sai hoặc báo lỗi định dạng.

# WRONG — reading as text
with open("captcha.png", "r") as f:  # Text mode
    content = f.read()  # Corrupted binary data

# RIGHT — reading as bytes
with open("captcha.png", "rb") as f:  # Binary mode
    content = f.read()
encoded = base64.b64encode(content).decode("ascii")

Xác thực ảnh base64 trước khi gửi

Validate ở phía client giúp phát hiện lỗi ngay, thay vì chờ CaptchaAI trả ERROR_* rồi debug ngược. Hàm dưới đây kiểm tra: có dính tiền tố data URI không, có decode được không, và kích thước/định dạng sau decode có hợp lệ không.

# validate.py
import base64
import io

def validate_captcha_image(b64_string):
    """Validate base64 image before submitting to CaptchaAI."""
    errors = []

    # Check for data URI prefix
    if b64_string.startswith("data:"):
        errors.append("Contains data URI prefix — strip it")
        b64_string = b64_string.split(",", 1)[1]

    # Try decoding
    try:
        decoded = base64.b64decode(b64_string)
    except Exception as e:
        return {"valid": False, "errors": [f"Invalid base64: {e}"]}

    # Check size
    size_kb = len(decoded) / 1024
    if size_kb < 1:
        errors.append(f"Image too small ({size_kb:.1f} KB) — likely corrupt")
    if size_kb > 500:
        errors.append(f"Image large ({size_kb:.1f} KB) — consider resizing")

    # Check image format
    if decoded[:8] == b'\x89PNG\r\n\x1a\n':
        fmt = "PNG"
    elif decoded[:3] == b'\xff\xd8\xff':
        fmt = "JPEG"
    elif decoded[:4] == b'GIF8':
        fmt = "GIF"
    elif decoded[:4] == b'RIFF':
        fmt = "WEBP"
    else:
        errors.append("Unknown image format")
        fmt = "unknown"

    return {
        "valid": len(errors) == 0,
        "format": fmt,
        "size_kb": round(size_kb, 1),
        "errors": errors,
    }

# Usage
result = validate_captcha_image(b64_string)
if not result["valid"]:
    print(f"Issues: {result['errors']}")
else:
    print(f"Valid {result['format']}, {result['size_kb']} KB")

Mẹo: chạy validate_captcha_image() ngay trong vòng lặp scraping, trước lệnh gọi API — lọc ảnh hỏng tại chỗ thay vì tốn một request cho ảnh chắc chắn bị từ chối.


Chọn định dạng ảnh phù hợp

Định dạng Tốt nhất cho Kích thước Chất lượng
PNG CAPTCHA văn bản, ảnh chụp màn hình Lớn hơn Không mất dữ liệu
JPEG CAPTCHA dạng ảnh chụp thực tế Nhỏ hơn Mất dữ liệu (dùng quality ≥ 85)
GIF CAPTCHA hoạt hình Thay đổi Màu sắc hạn chế
WEBP Trình duyệt hiện đại Nhỏ nhất Chất lượng tốt

Khuyến nghị chọn định dạng:

  • CAPTCHA văn bản → PNG (nén không mất dữ liệu, giữ nguyên cạnh ký tự)
  • CAPTCHA dạng ảnh chụp thực tế → JPEG với quality ≥ 85
  • Tránh nén JPEG quá tay — nguyên nhân phổ biến nhất của kết quả giải sai dù ảnh gốc rõ nét

Xử lý lỗi thường gặp

Tra nhanh mã lỗi API để biết sửa ở đâu, không cần đoán:

Vấn đề Nguyên nhân Cách xử lý
ERROR_WRONG_FILE_EXTENSION Dữ liệu base64 không hợp lệ Validate bằng validate_captcha_image() trước khi gửi
ERROR_TOO_BIG_CAPTCHA_FILESIZE Ảnh vượt quá 600 KB Resize hoặc nén ảnh trước khi mã hóa
ERROR_ZERO_CAPTCHA_FILESIZE Ảnh rỗng hoặc bị hỏng Kiểm tra lại bước tải/chụp ảnh có thành công không
Kết quả giải sai JPEG bị nén quá mức Dùng PNG hoặc JPEG với quality ≥ 85

Lỗi vẫn lặp lại sau khi sửa? Quay lại phần Ba lỗi mã hóa base64 ở trên — 9/10 case rơi vào một trong ba lỗi đó.


Câu hỏi thường gặp

Tổng hợp từ các ticket hỗ trợ thực tế về mã hóa base64.

Kích thước ảnh base64 tối đa CaptchaAI chấp nhận là bao nhiêu?

600 KB cho phần thân base64. Resize ảnh full-page từ Selenium trước khi mã hóa để tránh ERROR_TOO_BIG_CAPTCHA_FILESIZE.

Có bắt buộc nén ảnh trước khi gửi base64 không?

Không bắt buộc nếu ảnh dưới 600 KB. Nhưng nên:

  • Resize full-page screenshot xuống đúng vùng CAPTCHA trước khi mã hóa
  • Giữ PNG cho CAPTCHA văn bản, chỉ nén JPEG khi ảnh là photo thật

Vì sao ảnh chụp bằng Selenium báo ERROR_WRONG_FILE_EXTENSION dù ảnh hợp lệ?

Thường do mã hóa hai lần: element.screenshot_as_base64 đã trả về base64 sẵn, dùng luôn chuỗi đó thay vì gọi base64.b64encode() thêm lần nữa.

Ảnh CAPTCHA hoạt hình (GIF) gửi base64 có giải được không?

Có, cùng tham số method=base64, nhưng màu sắc hạn chế của GIF có thể ảnh hưởng độ chính xác so với PNG.


Hướng dẫn liên quan

Đọc thêm về cải thiện độ chính xác khi giải CAPTCHA OCRtiền xử lý ảnh CAPTCHA để tăng tỷ lệ giải đúng.


Mã hóa ảnh CAPTCHA đúng chuẩn trước khi gửi — bắt đầu dùng CaptchaAI.

Os comentários estão desativados para este artigo.