Scarnox · Blog

OCR captcha dạng ảnh và văn bản: cách đọc captcha bị méo

Captcha ảnh hiển thị một chuỗi ngắn gồm chữ hoặc số dưới dạng hình, đôi khi kèm nhiễu, xoay và các đường gợn sóng. Nhận dạng ký tự quang học (OCR) có thể đọc các phiên bản đơn giản của chúng bằng một công cụ mã nguồn mở như Tesseract. Độ chính xác phụ thuộc vào việc ảnh sạch đến đâu, nên phần lớn công việc nằm ở tiền xử lý. Hướng dẫn này trình bày một thiết lập Python chạy được, giải thích nó thất bại ở đâu, và nói rõ một điều: API đang hoạt động của Scarnox giải token cho widget PopularCaptcha, không giải captcha dạng ảnh sang chữ. Hãy lên kế hoạch cho OCR như code của riêng bạn, không phải một lệnh gọi API.

Khi nào OCR hiệu quả và khi nào không

OCR là lựa chọn hợp lý để thử trước khi văn bản:

Nó gặp khó với chữ bị xoay, chữ dính vào nhau, họa tiết nền, và các đường vẽ xuyên qua ký tự. Mỗi trường hợp đó cần một bước tiền xử lý riêng, và một số cần hẳn một mô hình khác. Hãy sẵn sàng đo độ chính xác thay vì cho rằng nó đúng.

Cài đặt công cụ

Bạn cần Python, file thực thi Tesseract và hai gói Python:

pip install pillow pytesseract

Tesseract là một bản cài đặt riêng. Trên Windows, dùng bộ cài đặt từ dự án Tesseract và đảm bảo file thực thi nằm trong PATH, hoặc trỏ pytesseract.pytesseract.tesseract_cmd tới nó.

Tiền xử lý, rồi đọc

Phần lớn độ chính xác đến từ đầu vào sạch. Chuỗi bước dưới đây chuyển sang thang xám, tăng độ tương phản, áp dụng ngưỡng cứng, phóng to ảnh và giới hạn đầu ra vào các ký tự captcha dùng:

from PIL import Image, ImageOps
import pytesseract

# Các ký tự captcha có thể dùng. Bỏ các ký tự dễ nhầm như 0/O và 1/I nếu captcha không dùng chúng.
ALLOWED = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789"

def read_text(path: str) -> str:
    img = Image.open(path)
    gray = ImageOps.grayscale(img)
    gray = ImageOps.autocontrast(gray)
    # Ngưỡng cứng: điểm sáng hơn 140 thành trắng, phần còn lại thành đen.
    bw = gray.point(lambda p: 255 if p > 140 else 0)
    # Tesseract đọc tốt hơn với ký tự lớn hơn.
    bw = bw.resize((bw.width * 3, bw.height * 3))
    config = f"--psm 7 -c tessedit_char_whitelist={ALLOWED}"  # psm 7: một dòng văn bản
    return pytesseract.image_to_string(bw, config=config).strip()

if __name__ == "__main__":
    print(read_text("sample_captcha.png"))

Giá trị ngưỡng 140 chỉ là điểm xuất phát. Hãy in ảnh đã xử lý, so sánh với ảnh gốc, và điều chỉnh cho đến khi các ký tự rõ nét và nền sạch.

Đo độ chính xác trước khi dựa vào nó

Một lần đọc đúng trên một ảnh không chứng minh được gì. Hãy lưu một tập captcha có đáp án đã biết, chạy hàm trên tất cả, rồi đếm số lần khớp:

def accuracy(samples: dict[str, str]) -> float:
    # samples ánh xạ đường dẫn file tới văn bản đúng
    hits = sum(read_text(path) == truth for path, truth in samples.items())
    return hits / len(samples)

labelled = {
    "samples/0001.png": "K7PQ2",
    "samples/0002.png": "M3XN9",
}
print(f"accuracy: {accuracy(labelled):.0%}")

Theo dõi con số này mỗi khi bạn thay đổi tiền xử lý. Nếu nó vẫn thấp sau nhiều lần thay đổi, OCR có lẽ là công cụ sai cho kiểu captcha đó, và bạn nên xem xét một cách tiếp cận khác.

Những chỗ nó hỏng

Danh sách kiểm tra tiền xử lý

Khi một lần đọc thất bại, hãy làm lần lượt các bước sau. Mỗi lần chỉ đổi một thứ để biết bước nào đã giúp:

  1. Kiểm tra kích thước đầu vào. Captcha rất nhỏ thường đọc tốt hơn sau khi phóng to 3 lần.
  2. Chuyển sang thang xám và kéo giãn độ tương phản để chữ nổi bật.
  3. Áp dụng ngưỡng, thử vài giá trị trước khi chọn một.
  4. Loại bỏ nhiễu đốm bằng bộ lọc trung vị, rồi áp dụng ngưỡng lại nếu cần.
  5. Cắt ảnh về vùng chữ để nền không làm công cụ bối rối.
  6. Giới hạn bộ ký tự vào bộ mà captcha dùng.
  7. Thử một chế độ phân đoạn trang khác nếu chữ nằm rải rác hoặc xếp chồng.

Giữ thứ tự và các thiết lập trong kiểm soát phiên bản, cạnh các mẫu đã gán nhãn. Một pipeline tiền xử lý là code, và nó cần được review như code.

OCR hay một mô hình tự chạy

OCR cổ điển nhanh và chạy được trên laptop, nhưng dễ vỡ khi captcha đổi kiểu. Mô hình ảnh được huấn luyện trên tập đã gán nhãn của riêng bạn có thể xử lý được nhiều biến thể hơn, với cái giá là phải thu thập dữ liệu và chạy suy luận. Cả hai đều do bạn tự xây và bảo trì. Hiện chưa có cái nào là endpoint Scarnox được host, nên hãy lên kế hoạch hạ tầng trước khi chọn một.

Scarnox làm gì và không làm gì ở đây

API đang hoạt động của Scarnox giải token cho widget PopularCaptcha. Request là POST https://api.scarnox.com/api/tasks/create với loại task PopularCaptcha, một sitekey và URL trang, và phản hồi là một token cho trường form. Đó là một công việc khác với việc đọc chữ trong ảnh, và Scarnox hiện không cung cấp endpoint ảnh sang chữ. Nếu vấn đề của bạn là captcha ảnh, hãy dùng OCR hoặc một mô hình tự chạy, và xem các hướng dẫn khác để biết Scarnox bao quát những gì. Bạn có thể tạo tài khoản và bắt đầu với tín dụng dùng thử miễn phí, không cần thẻ, cho các luồng PopularCaptcha mà nó hỗ trợ. Giá hiện tại nằm trên trang giá.

Các mục đích hợp pháp

Đừng dùng OCR để vượt captcha trên một trang không cho phép truy cập tự động. Captcha dạng ảnh tồn tại chính là để làm chậm đúng hành vi đó.

Bước tiếp theo