ERROR_ZERO_CAPTCHA_FILESIZE при нормальном на вид изображении почти всегда означает не капчу, а кривой base64: лишний префикс data:image/..., повторное кодирование уже закодированной строки или чтение файла как текста. Ниже — код на Python для каждого сценария и функция валидации, которая ловит эти ошибки заранее.
Три причины закрывают почти все жалобы на кодирование: префикс
data:image/...не срезан, строка закодирована в base64 дважды или файл прочитан в текстовом режиме вместо бинарного. Проверьте эти три пункта первыми, до разбора логовin.php.
Как отправить CAPTCHA в base64 через API
CaptchaAI принимает изображение CAPTCHA напрямую как base64-строку в теле запроса, без промежуточной загрузки файла на сервер, — параметр method=base64:
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()
В ответе (при status: 1) поле request содержит ID задачи — сохраните его: тот же ID передаётся параметром id при опросе res.php до получения решения.
Кодирование файла с диска
Частый случай — картинка уже сохранена локально:
# 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")
Длину строки стоит логировать отдельно от самого запроса — она первой сигнализирует о проблеме, если open() внезапно открыл не тот файл.
Кодирование изображения по URL
Если CAPTCHA отдаётся ссылкой, скачайте её и проверьте, что сервер вернул картинку, а не HTML при истёкшей сессии:
# 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")
Кодирование скриншота из Selenium
Когда прямой ссылки на картинку нет (canvas, наложение через CSS), проще снять скриншот нужного элемента:
# 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")
Снимая весь driver.get_screenshot_as_png(), помните: в кадр может попасть чужая форма с персональными данными. Кодируйте только нужный регион (152-ФЗ / GDPR).
Частые ошибки кодирования
Три сценария ниже покрывают почти весь трафик тикетов про кодирование — от самого частого к самому редкому.
Ошибка 1: лишний префикс data URI
# 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
Эта ошибка чаще всего приходит из готовых сниппетов «как получить base64 картинки», скопированных из фронтенд-кода — там префикс нужен для <img src>, а для in.php его нужно срезать.
Ошибка 2: двойное base64-кодирование
# 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
Проверить на глаз почти невозможно: обе строки выглядят как валидный base64, а validate_captcha_image() первой же строкой сообщит Invalid base64 только на грубой поломке — на двойном кодировании decode пройдёт, но картинка получится битой.
Ошибка 3: чтение файла как текста, а не как байтов
# 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")
Проверка base64 перед отправкой
Функция ниже ловит все три ошибки до отправки в in.php — дешевле поймать проблему локально, чем тратить поток на заведомо неверный запрос:
# 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")
Пример: проверка кодирования в CI для распределённой команды
Команда, где часть тестировщиков сидит в Европе, а стенды поднимаются в дата-центрах Казахстана или Центральной Азии, регулярно ловит одну и ту же проблему: локально скриншот кодируется нормально, а на CI-раннере в другом регионе — нет, потому что раннер тянет другую версию Pillow или запускает Selenium в другом режиме рендеринга. Добавлять validate_captcha_image() в сам API-клиент уже поздно: к этому моменту поток уже потрачен на заведомо неверный запрос.
Практичнее вынести проверку в отдельный шаг CI, до любого обращения к in.php:
- Прогоняйте каждый новый скриншот через
validate_captcha_image()в юнит-тесте, а не только вручную при отладке. - Логируйте поля
formatиsize_kbиз результата — по ним регрессия видна быстрее, чем по HTTP-ответуin.php. - Если раннеры разнесены по регионам, добавляйте
retryс экспоненциальной задержкой на сам запрос кin.php, а не на шаг кодирования: кодирование почти никогда не флапает, а сеть между регионами — да. - Никогда не логируйте саму base64-строку целиком: в кадр скриншота может попасть форма с персональными данными (152-ФЗ / GDPR) — храните только метаданные из
result.
Какой формат изображения выбрать
| Формат | Когда использовать | Вес файла | Качество |
|---|---|---|---|
| PNG | Текстовые CAPTCHA, скриншоты элементов | Больше | Без потерь |
| JPEG | CAPTCHA на основе фотографий | Меньше | С потерями (качество ≥ 85) |
| GIF | Анимированные CAPTCHA | Переменный | Ограниченная палитра цветов |
| WEBP | Современные браузеры | Самый компактный | Хорошее качество |
Как выбрать формат:
- Текстовая CAPTCHA — PNG: точность решения важнее веса файла, сжатие без потерь сохраняет края символов.
- Скриншот с мобильного канала или высокая задержка до региона хостинга (например, Казахстан/Центральная Азия при скрапере из Европы) — WEBP: риск таймаута на
in.phpниже. - Анимированная CAPTCHA — GIF, но сначала прогоните файл через
validate_captcha_image(): формат там определяется по сигнатуре байтов, а не по расширению файла, и подмену легко пропустить глазами.
Диагностика ошибок API
Коды ошибок in.php, характерные именно для этого сценария, и что с ними делать:
| Ошибка | Причина | Решение |
|---|---|---|
ERROR_WRONG_FILE_EXTENSION |
Некорректные base64-данные | Проверьте строку функцией validate_captcha_image() |
ERROR_TOO_BIG_CAPTCHA_FILESIZE |
Изображение больше 600 КБ | Уменьшите размер или сожмите перед кодированием |
ERROR_ZERO_CAPTCHA_FILESIZE |
Пустое или повреждённое изображение | Убедитесь, что загрузка прошла успешно |
| Неверный результат решения | Слишком сильно сжатый JPEG | Используйте PNG или JPEG с качеством ≥ 85 |
Если код ошибки не совпал ни с одной строкой таблицы — это, скорее всего, не про кодирование: проверьте
keyи текущий баланс потоков в панели управления, прежде чем снова отлаживать base64.
Часто задаваемые вопросы
Какой максимальный размер base64-строки принимает CaptchaAI?
600 КБ для декодированного изображения. Если скриншот больше:
- уменьшите разрешение перед кодированием;
- или обрежьте кадр до нужного элемента, а не всей страницы.
Почему ERROR_ZERO_CAPTCHA_FILESIZE появляется при рабочем скриншоте?
Чаще всего файл открыт в текстовом режиме ("r" вместо "rb"), байты повреждаются при чтении. Проверьте функцию чтения и validate_captcha_image().
Быстрая проверка перед тем, как копать глубже: сохраните
base64.b64decode(b64_string)локально в файл и откройте как картинку — не загружайте строку в сторонние онлайн-декодеры. Если файл не открывается — проблема в кодировании, а не в CaptchaAI.
Нужно ли сжимать PNG перед кодированием?
Обычно нет — PNG уже без потерь. Если payload великоват, обрежьте изображение до элемента, а не сжимайте весь скриншот.
Как проверить base64-строку перед отправкой?
Коротко — так же, как это делает validate_captcha_image():
- Декодируйте строку через
base64.b64decode()в try/except. - Сверьте первые байты декодированных данных с сигнатурой формата (PNG/JPEG/GIF/WEBP).
- Проверьте размер в КБ — меньше 1 КБ или больше 500 КБ почти всегда означает проблему.
Можно ли отправлять CAPTCHA в формате SVG?
Нет, только растровые форматы. Сконвертируйте SVG в PNG заранее — например, через Pillow или cairosvg.
Что логировать при ошибке кодирования, если нельзя сохранять сам base64?
Только результат validate_captcha_image(), без самой строки:
- поле
format— распознанный тип изображения; - поле
size_kb— размер после декодирования; - список
errors— этого достаточно, чтобы отличить сломанное кодирование от сетевой проблемы, и не тянет за собой персональные данные из скриншота.
Похожие материалы
Кодируйте CAPTCHA правильно с первого раза — начните с CaptchaAI.