So Sánh

CAPTCHA văn bản và CAPTCHA hình ảnh: So sánh giữa nhà phát triển

Câu trả lời ngắn: CAPTCHA văn bản dễ triển khai và rẻ hơn nhiều khi giải tự động, còn CAPTCHA hình ảnh chặn bot tốt hơn nhưng khiến người dùng thật bỏ cuộc nhiều hơn. Với team QA hoặc scraping ở TP.HCM chạy hàng nghìn form mỗi ngày, khác biệt đó quyết định cả kiến trúc lẫn hóa đơn hàng tháng. Bài đi theo thứ tự một dev cần: so sánh, cơ chế, code nhận diện, cách giải qua API.


Bảng so sánh nhanh hai loại CAPTCHA

Số liệu dưới đây dựa trên đo đạc nội bộ và báo cáo từ người dùng tại thời điểm ghi nhận. Kết quả thực tế thay đổi theo môi trường, khối lượng và thời điểm.

Tiêu chí CAPTCHA văn bản CAPTCHA hình ảnh
Mức độ bảo mật Thấp — OCR đọc được phần lớn ký tự biến dạng Cao — cần nhận dạng đối tượng
Thời gian người dùng giải 5–10 giây 10–30 giây
Tỷ lệ nhập sai (người thật) 15–20% 8–15%
Khả năng truy cập Kém với người khiếm thị Rất kém với người khiếm thị
Trên thiết bị di động Trung bình (ký tự nhỏ, dễ gõ nhầm) Tốt (chạm chọn ô)
Độ khó tự động hóa Dễ (chỉ cần OCR) Khó (phải phân loại ảnh)
Chi phí triển khai Miễn phí nếu tự host Miễn phí hoặc trả phí (SDK ngoài)
Chi phí giải qua dịch vụ $0,50–$1,00 cho mỗi 1.000 lần $1,50–$3,00 cho mỗi 1.000 lần
Thu thập dữ liệu người dùng Không Có thể huấn luyện mô hình ML (reCAPTCHA)
Công sức tích hợp Tối thiểu (sinh ảnh phía server) Trung bình (nhúng SDK JavaScript)

Dòng "thu thập dữ liệu" hay bị bỏ qua: CAPTCHA văn bản tự host không đẩy dữ liệu hành vi ra bên thứ ba — điểm cộng khi trả lời câu hỏi tuân thủ theo Nghị định 13/2023/NĐ-CP.


CAPTCHA văn bản hoạt động thế nào

Chuỗi ký tự bóp méo được render thành ảnh, người dùng đọc rồi gõ lại vào ô input. Ba hệ quả kỹ thuật:

  • Không SDK JavaScript, không request ra ngoài
  • Toàn bộ vòng đời nằm trên server của bạn
  • Không chấm điểm hành vi, chỉ so khớp chuỗi

Các kỹ thuật làm méo ký tự phổ biến

Kỹ thuật Mục đích
Bóp méo ký tự Uốn cong chữ để OCR đơn giản đọc sai
Nhiễu nền Thêm đường kẻ, chấm, dải màu sau chữ
Chồng ký tự Cho chữ cái liền nhau đè lên nhau, chống tách ký tự
Ngẫu nhiên hóa phông chữ Đổi phông và cỡ chữ mỗi lần sinh thử thách
Đổi màu ngẫu nhiên Random màu chữ và nền

Vòng đời một thử thách văn bản

Server generates random string (e.g., "X7mK9p")
    ↓
Applies distortion: warping, noise, overlap
    ↓
Renders as PNG/JPEG image
    ↓
User reads characters, types into input field
    ↓
Server compares input against stored string (case-insensitive usually)

Điểm yếu nằm ở bước cuối: chuỗi gốc lưu trên server, so sánh nguyên văn — bảo mật chỉ phụ thuộc vào việc OCR có đọc nổi ảnh không.


CAPTCHA hình ảnh hoạt động thế nào

Một lưới ảnh kèm câu lệnh, người dùng chọn các ô khớp mô tả. Khác biệt lớn nhất so với loại văn bản:

  • Việc chấm điểm nằm phía nhà cung cấp, không phải server của bạn
  • Trang của bạn chỉ nhận lại token để verify

Các dạng thử thách hình ảnh thường gặp

Dạng Thử thách Nhà cung cấp
Chọn theo lưới "Chọn ô có đèn giao thông" reCAPTCHA v2
Gán nhãn ảnh "Nhấp vào ảnh có xe buýt" hCaptcha
Đếm đối tượng "Có bao nhiêu xe đạp trong ảnh?" Tùy chỉnh
Xoay ảnh "Xoay ảnh về đúng chiều" FunCaptcha

Vòng đời một thử thách hình ảnh

Server selects images from a labeled dataset
    ↓
Presents 3×3 or 4×4 grid with a text prompt
    ↓
User clicks matching images
    ↓
Server validates selections against ground truth
    ↓
If fading images: new images load in place of selected ones (multi-round)

Cơ chế nhiều vòng — ảnh mới thay chỗ ảnh vừa chọn — đẩy thời gian giải lên 10–30 giây và khiến người dùng 4G sóng yếu bỏ form.


Nhận diện trang đang dùng loại CAPTCHA nào

Trước khi chọn cách giải, xác định mình gặp loại nào. Hai đoạn dưới tải HTML rồi phân loại theo dấu hiệu đặc trưng.

Nhận diện bằng Python

import requests
from bs4 import BeautifulSoup
import re

def detect_captcha_type(url):
    """Detect whether page uses text or image CAPTCHA."""
    response = requests.get(url, timeout=10)
    soup = BeautifulSoup(response.text, "html.parser")
    html = response.text

    result = {"text_captcha": False, "image_captcha": False, "provider": None}

    # Check for reCAPTCHA (image-based)
    if "google.com/recaptcha" in html or "g-recaptcha" in html:
        result["image_captcha"] = True
        result["provider"] = "reCAPTCHA"
        return result

    # Check for hCaptcha (image-based)
    if "hcaptcha.com" in html or "h-captcha" in html:
        result["image_captcha"] = True
        result["provider"] = "hCaptcha"
        return result

    # Check for text CAPTCHA patterns
    captcha_images = soup.find_all("img", attrs={
        "src": re.compile(r"captcha", re.I)
    })
    captcha_inputs = soup.find_all("input", attrs={
        "name": re.compile(r"captcha", re.I)
    })

    if captcha_images and captcha_inputs:
        # Image with text input = text CAPTCHA
        result["text_captcha"] = True
        result["provider"] = "custom text CAPTCHA"
        return result

    # Check for FunCaptcha (image-based rotation)
    if "funcaptcha" in html.lower() or "arkoselabs" in html.lower():
        result["image_captcha"] = True
        result["provider"] = "FunCaptcha"
        return result

    return result

captcha = detect_captcha_type("https://staging.example.com/qa-login")
print(captcha)

Nhận diện bằng Node.js

const axios = require("axios");
const cheerio = require("cheerio");

async function detectCaptchaType(url) {
    const { data: html } = await axios.get(url, { timeout: 10000 });
    const $ = cheerio.load(html);

    const result = { textCaptcha: false, imageCaptcha: false, provider: null };

    // reCAPTCHA detection
    if (html.includes("google.com/recaptcha") || html.includes("g-recaptcha")) {
        result.imageCaptcha = true;
        result.provider = "reCAPTCHA";
        return result;
    }

    // hCaptcha detection
    if (html.includes("hcaptcha.com") || html.includes("h-captcha")) {
        result.imageCaptcha = true;
        result.provider = "hCaptcha";
        return result;
    }

    // Text CAPTCHA: image + input with "captcha" in name/class
    const captchaImgs = $("img[src*='captcha' i]").length;
    const captchaInputs = $("input[name*='captcha' i]").length;

    if (captchaImgs > 0 && captchaInputs > 0) {
        result.textCaptcha = true;
        result.provider = "custom text CAPTCHA";
        return result;
    }

    return result;
}

detectCaptchaType("https://staging.example.com/qa-login").then(console.log);

Quy tắc đơn giản: thẻ img chứa "captcha" đi kèm ô input cùng tên gần như chắc chắn là CAPTCHA văn bản tự host; thấy script nhà cung cấp thì đó là họ hình ảnh hoặc token.


Giải CAPTCHA văn bản bằng CaptchaAI

CAPTCHA văn bản vẫn là ảnh: chuỗi bóp méo render thành PNG hoặc JPEG. API OCR hình ảnh của CaptchaAI xử lý trực tiếp — không sitekey, không trình duyệt.

import requests
import base64
import time

API_KEY = "YOUR_API_KEY"

# Get the CAPTCHA image
captcha_url = "https://example.com/captcha.png"
image_data = requests.get(captcha_url).content
b64 = base64.b64encode(image_data).decode()

# Submit to CaptchaAI
submit = requests.post("https://ocr.captchaai.com/in.php", data={
    "key": API_KEY,
    "method": "base64",
    "body": b64,
    "json": 1,
})
task_id = submit.json()["request"]

# Poll for result
for _ in range(30):
    time.sleep(3)
    resp = requests.get("https://ocr.captchaai.com/res.php", params={
        "key": API_KEY,
        "action": "get",
        "id": task_id,
        "json": 1,
    }).json()

    if resp.get("status") == 1:
        print(f"CAPTCHA text: {resp['request']}")
        break

Luồng chỉ có hai chặng: gửi ảnh base64 tới in.php, rồi polling res.php tới khi status trả về 1. CaptchaAI hỗ trợ hơn 27.500 biến thể CAPTCHA hình ảnh: chữ bóp méo, phép toán đơn giản, nhận dạng ký tự.

CAPTCHA dạng token đi đường khác: gửi sitekeypageurl, nhận token rồi đặt vào form — pipeline gặp cả hai họ cần hai nhánh riêng.

Chi phí thực tế trông ra sao

CaptchaAI tính tiền theo thread (luồng giải đồng thời), không theo từng lần giải — chi phí bám vào mức đồng thời, không phải tổng số CAPTCHA. Một team ở Hà Nội theo dõi giá sàn thương mại điện tử xử lý ~20.000 ảnh CAPTCHA văn bản mỗi ngày nhưng chỉ cần 15 request song song — vẫn nằm gọn trong STANDARD ($30/tháng, 15 thread); cùng khối lượng trên form reCAPTCHA v2 (giải lâu hơn) cần ADVANCE ($90/tháng, 50 thread). Giá niêm yết bằng USD; gói nhỏ nhất là BASIC ($15/tháng, 5 thread).

Phạm vi hỗ trợ: reCAPTCHA v2/v3, Cloudflare Turnstile, Cloudflare Challenge, GeeTest v3, ảnh/OCR, grid image, BLS CAPTCHA; CaptchaFox, Friendly Captcha, Lemin ở giai đoạn beta. CaptchaAI không hỗ trợ hCaptcha và FunCaptcha (Arkose Labs); GeeTest v4 mới sắp ra mắt.


Chọn loại nào cho sản phẩm của bạn

Đối chiếu tình huống của bạn:

Tình huống Lựa chọn hợp lý
Tự host, không phụ thuộc bên ngoài CAPTCHA văn bản
Dữ liệu phải nằm trong hạ tầng của bạn CAPTCHA văn bản
Lưu lượng bot thấp, chỉ cần chặn spam cơ bản CAPTCHA văn bản
Cần mức chặn bot mạnh hơn rõ rệt CAPTCHA hình ảnh
Form nhạy cảm: đăng nhập, thanh toán CAPTCHA hình ảnh
Chấp nhận ma sát để đổi lấy bảo vệ CAPTCHA hình ảnh
Muốn dịch vụ tự cập nhật CAPTCHA hình ảnh
Chỉ cần lọc bot, không bắt thao tác Không dùng cả hai

Hàng cuối đáng cân nhắc nhất: reCAPTCHA v3 và Cloudflare Turnstile không bắt thao tác nên thường ít rơi form hơn, và đều được CaptchaAI hỗ trợ.


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

CAPTCHA văn bản còn đáng dùng cho website mới không?

Hầu như không, nếu đối thủ là bot có đầu tư: OCR hiện nay đọc được đa số ảnh chữ biến dạng tiêu chuẩn. Bóp méo mạnh hơn chặn thêm bot, nhưng người thật cũng nhập sai nhiều hơn. Nó chỉ hợp lý cho form nội bộ ít lưu lượng.

Giải CAPTCHA văn bản có cần trình duyệt không?

Không. Chỉ cần tải ảnh, mã hóa base64 rồi gửi tới endpoint OCR — không Selenium, không Playwright, không chế độ headless. Đó là lý do loại này rẻ và nhanh hơn trong pipeline scraping.

CaptchaAI có giải được hCaptcha không?

Không, và cũng không hỗ trợ FunCaptcha (Arkose Labs). Đoạn code trong bài vẫn nhận diện được chúng, nhưng bạn phải tìm hướng xử lý khác.

Trang của tôi vừa có ảnh chữ vừa có reCAPTCHA thì xử lý sao?

Chạy đoạn nhận diện ở trên rồi rẽ nhánh: nhánh OCR gửi ảnh base64, nhánh token gửi sitekeypageurl. Một API key dùng chung, và số thread trong gói là tài nguyên chung của cả pipeline.

Nên chọn gói nào cho khoảng 10.000 CAPTCHA mỗi ngày?

Phụ thuộc mức đồng thời, không phải tổng số. Mỗi thread giải không giới hạn, nên hãy ước lượng số request song song giờ cao điểm rồi chọn gói phủ được con số đó: STANDARD ($30/tháng, 15 thread), hoặc ADVANCE ($90/tháng, 50 thread) nếu cần nhiều luồng hơn.


Kết luận

CAPTCHA văn bản rẻ khi triển khai và dễ giải bằng OCR; CAPTCHA hình ảnh khó tự động hóa hơn, bảo vệ tốt hơn, nhưng thu phí bằng sự kiên nhẫn của người dùng thật. Trong pipeline tự động hóa, loại văn bản chỉ cần một lần gọi OCR hình ảnh của CaptchaAI; loại hình ảnh cần bộ giải chuyên biệt. Xu hướng chung vẫn là chuyển sang CAPTCHA vô hình để bỏ hẳn thao tác thủ công.

Bài viết liên quan

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