Нужен рабочий скрипт для CAPTCHA, а не мануал с нуля? Пять сценариев на Python и Node.js отправляют задачу в API CaptchaAI, опрашивают res.php и возвращают токен — удобно фрилансерам и командам в России, Беларуси и Казахстане. Каждый сценарий закрывает свою задачу: разовый запуск из терминала, встраивание в существующий пайплайн или параллельный прогон сотен CAPTCHA одновременно — ниже видно, что решает каждый вариант и на что обратить внимание при переносе в продакшен.
Пригодится для:
- тестов форм за Cloudflare Turnstile;
- парсинга staging-окружений с CAPTCHA;
- cron-задач с бюджетом в долларах.
Сравнение ниже помогает выбрать нужный сценарий сразу, не читая все пять целиком.
| Сценарий | Тип CAPTCHA | Язык |
|---|---|---|
| 1 | reCAPTCHA v2 | Python |
| 2 | Cloudflare Turnstile | Python |
| 3 | Картиночная CAPTCHA | Python |
| 4 | Пакетное решение | Python |
| 5 | Универсальный решатель | Node.js |
Совет: собирайте при парсинге только данные, которые вы вправе обрабатывать — общий принцип 152-ФЗ и GDPR.
Все пять сценариев используют один и тот же цикл: in.php принимает параметры и возвращает task_id, res.php по этому ID отдаёт CAPCHA_NOT_READY или готовый токен. В коде ниже API_KEY захардкожен для наглядности — в реальном проекте вынесите его в переменную окружения или секрет-хранилище, чтобы не закоммитить ключ в репозиторий.
Сценарий 1: токен reCAPTCHA v2 одной командой
Отправляет sitekey и адрес страницы, печатает токен для поля g-recaptcha-response формы. site_key берётся из атрибута data-sitekey виджета на странице, page_url — адрес, где виджет отображается: оба параметра обязательны для метода userrecaptcha. Точки во время опроса и строка Task ID в выводе — это не декоративный вывод, а способ увидеть, что скрипт ждёт ответ res.php, а не завис.
#!/usr/bin/env python3
"""Solve reCAPTCHA v2 and print the token."""
import requests
import time
import sys
API_KEY = "YOUR_API_KEY"
def solve_recaptcha_v2(site_key, page_url):
resp = requests.get("https://ocr.captchaai.com/in.php", params={
"key": API_KEY,
"method": "userrecaptcha",
"googlekey": site_key,
"pageurl": page_url
})
if not resp.text.startswith("OK|"):
print(f"Error: {resp.text}", file=sys.stderr)
sys.exit(1)
task_id = resp.text.split("|")[1]
print(f"Task ID: {task_id}")
for _ in range(60):
time.sleep(5)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY, "action": "get", "id": task_id
})
if result.text == "CAPCHA_NOT_READY":
print(".", end="", flush=True)
continue
if result.text.startswith("OK|"):
print()
return result.text.split("|")[1]
print(f"\nError: {result.text}", file=sys.stderr)
sys.exit(1)
print("\nTimeout", file=sys.stderr)
sys.exit(1)
if __name__ == "__main__":
if len(sys.argv) != 3:
print(f"Usage: {sys.argv[0]} <site_key> <page_url>")
sys.exit(1)
token = solve_recaptcha_v2(sys.argv[1], sys.argv[2])
print(token)
Запуск
python solve_recaptcha.py "6Le-wvkS..." "https://example.com/form"
Сценарий 2: Cloudflare Turnstile без лишнего кода
Тот же цикл опроса, но короче — без лишнего вывода. Подходит, когда скрипт запускается внутри более крупного пайплайна: при ошибке функция поднимает исключение, которое можно поймать выше по стеку, вместо того чтобы печатать сообщение и завершать процесс. Замените site_key в вызове solve_turnstile на значение своего сайта — оно уникально для домена.
#!/usr/bin/env python3
"""Solve Cloudflare Turnstile and print the token."""
import requests
import time
API_KEY = "YOUR_API_KEY"
def solve_turnstile(site_key, page_url):
resp = requests.get("https://ocr.captchaai.com/in.php", params={
"key": API_KEY,
"method": "turnstile",
"sitekey": site_key,
"pageurl": page_url
})
task_id = resp.text.split("|")[1]
for _ in range(60):
time.sleep(5)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY, "action": "get", "id": task_id
})
if result.text == "CAPCHA_NOT_READY": continue
if result.text.startswith("OK|"): return result.text.split("|")[1]
raise Exception(result.text)
raise TimeoutError()
token = solve_turnstile("0x4AAAAA...", "https://example.com")
print(token)
Сценарий 3: картиночная CAPTCHA из файла или по ссылке
Принимает файл или URL на изображение, кодирует в base64 — для капч с коротким текстом. Скрипт сам определяет источник по префиксу http, так что один и тот же вызов работает и с локальным файлом, и с прямой ссылкой на картинку. Для искажённого текста или сложного фона доля успешных решений ниже, чем для чистого текста — если результат стабильно расходится с ожидаемым, сначала проверьте качество исходного изображения.
#!/usr/bin/env python3
"""Solve an image CAPTCHA from a file or URL."""
import requests
import base64
import time
import sys
API_KEY = "YOUR_API_KEY"
def solve_image(image_source):
# Load image
if image_source.startswith("http"):
img_data = requests.get(image_source).content
else:
with open(image_source, "rb") as f:
img_data = f.read()
img_b64 = base64.b64encode(img_data).decode()
resp = requests.get("https://ocr.captchaai.com/in.php", params={
"key": API_KEY,
"method": "base64",
"body": img_b64
})
task_id = resp.text.split("|")[1]
for _ in range(30):
time.sleep(5)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY, "action": "get", "id": task_id
})
if result.text == "CAPCHA_NOT_READY": continue
if result.text.startswith("OK|"): return result.text.split("|")[1]
raise Exception(result.text)
raise TimeoutError()
if __name__ == "__main__":
text = solve_image(sys.argv[1])
print(text)
Запуск
python solve_image.py captcha.png
python solve_image.py "https://example.com/captcha.jpg"
Сценарий 4: пакетное решение через ThreadPoolExecutor
Пять потоков (max_workers=5) укладываются в тариф BASIC ($15/мес, 5 потоков). Если задач больше, поднимите max_workers до числа потоков в вашем тарифе: ThreadPoolExecutor сам поставит остальные задачи в очередь и запустит их по мере освобождения воркеров, так что план с большим числом потоков даёт больше одновременных решений. Функция solve_batch отдаёт список словарей с полями url, token (или error) и status — удобно сразу писать в лог или в базу, не разбирая вывод построчно.
#!/usr/bin/env python3
"""Solve multiple CAPTCHAs concurrently."""
import requests
import time
from concurrent.futures import ThreadPoolExecutor, as_completed
API_KEY = "YOUR_API_KEY"
def solve_one(site_key, page_url):
resp = requests.get("https://ocr.captchaai.com/in.php", params={
"key": API_KEY, "method": "userrecaptcha",
"googlekey": site_key, "pageurl": page_url
})
task_id = resp.text.split("|")[1]
for _ in range(60):
time.sleep(5)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY, "action": "get", "id": task_id
})
if result.text == "CAPCHA_NOT_READY": continue
if result.text.startswith("OK|"): return result.text.split("|")[1]
raise Exception(result.text)
raise TimeoutError()
def solve_batch(tasks, max_workers=5):
"""
tasks: list of (site_key, page_url) tuples
Returns: list of tokens
"""
results = []
with ThreadPoolExecutor(max_workers=max_workers) as executor:
futures = {
executor.submit(solve_one, sk, url): (sk, url)
for sk, url in tasks
}
for future in as_completed(futures):
sk, url = futures[future]
try:
token = future.result()
results.append({"url": url, "token": token, "status": "ok"})
except Exception as e:
results.append({"url": url, "error": str(e), "status": "failed"})
return results
# Example
tasks = [
("6Le-wvkS...", "https://example.com/page1"),
("6Le-wvkS...", "https://example.com/page2"),
("6Le-wvkS...", "https://example.com/page3"),
]
results = solve_batch(tasks)
for r in results:
print(f"{r['url']}: {r['status']}")
Сценарий 5: универсальный решатель на Node.js
Для Node.js: передайте method, отправку и опрос модуль возьмёт на себя. Функция solve принимает произвольный набор параметров API — удобно, если проект уже смешивает несколько типов CAPTCHA и не хочется дублировать цикл опроса под каждый из них. Закомментированные примеры в конце файла показывают вызов для reCAPTCHA v2 и Turnstile — раскомментируйте нужный и подставьте свои значения sitekey/googlekey и pageurl.
#!/usr/bin/env node
// Solve any CAPTCHA type from the command line
const axios = require("axios");
const API_KEY = "YOUR_API_KEY";
async function solve(params) {
params.key = API_KEY;
const submit = await axios.get("https://ocr.captchaai.com/in.php", {
params,
});
if (!submit.data.startsWith("OK|")) throw new Error(submit.data);
const taskId = submit.data.split("|")[1];
while (true) {
await new Promise((r) => setTimeout(r, 5000));
const result = await axios.get("https://ocr.captchaai.com/res.php", {
params: { key: API_KEY, action: "get", id: taskId },
});
if (result.data === "CAPCHA_NOT_READY") continue;
if (result.data.startsWith("OK|")) return result.data.split("|")[1];
throw new Error(result.data);
}
}
// Usage examples:
// Solve reCAPTCHA v2
// solve({ method: "userrecaptcha", googlekey: "SITE_KEY", pageurl: "URL" })
// Solve Turnstile
// solve({ method: "turnstile", sitekey: "SITE_KEY", pageurl: "URL" })
module.exports = { solve };
Проверка баланса перед запуском
Проверяйте баланс перед cron-задачами — пустой счёт вернёт ошибку вместо токена. Поставьте эту проверку первым шагом в cron-задаче или CI-джобе: если баланс на нуле, скрипт сразу сообщит об этом, вместо того чтобы полчаса безуспешно опрашивать res.php. Число в ответе — это баланс без знака валюты, $ в примере добавлен только для вывода в консоль.
#!/usr/bin/env python3
"""Check CaptchaAI account balance."""
import requests
API_KEY = "YOUR_API_KEY"
resp = requests.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY,
"action": "getbalance"
})
print(f"Balance: ${resp.text}")
Что добавить перед продакшеном
Скрипты выше — рабочая база, а не готовый продакшен-сервис. Перед тем как поставить их в cron или в бэкенд, обычно добавляют три вещи:
- Логирование. Пишите
task_id, время отправки и итоговый статус в файл или систему мониторинга — при разборе инцидента это быстрее, чем перечитывать вывод в терминале. - Повтор при сетевых сбоях.
requests.getможет упасть с таймаутом ещё до ответаin.php— оберните вызов вtry/exceptс небольшой задержкой между повторами, а не давайте скрипту падать целиком. - Разбор кодов ошибок.
res.phpвозвращает не толькоCAPCHA_NOT_READY:ERROR_ZERO_BALANCEтребует пополнения баланса,ERROR_WRONG_USER_KEYиERROR_KEY_DOES_NOT_EXIST— проверки API-ключа. Реакция на каждый код должна быть своя, а не один общий повтор запроса.
Частые вопросы про автоматизацию CAPTCHA
Нужно ли дорабатывать скрипты для продакшена?
Да: добавьте логирование. Пакетный сценарий уже обрабатывает ошибки по задаче.
Что делать, если res.php долго возвращает CAPCHA_NOT_READY?
10–20 секунд — норма. Дольше — сверьте sitekey и pageurl со страницей.
Сколько потоков нужно для сотен CAPTCHA в час?
Ориентир: ADVANCE ($90/мес, 50 потоков) — сотни задач reCAPTCHA v2 в час; больше нужно — PREMIUM ($170/мес) или CORPORATE ($240/мес).
Сколько стоит запускать эти скрипты?
По потокам: от BASIC ($15/мес, 5 потоков) до ENTERPRISE ($300/мес, 200 потоков), выше — линейка VIP.
Что означает ошибка ERROR_ZERO_BALANCE?
Баланс закончился — пополните его в панели управления CaptchaAI.
Связанные руководства
Когда пять сценариев выше станут частью более крупного пайплайна, пригодятся смежные темы: автоматический вход с обработкой CAPTCHA — если CAPTCHA стоит перед формой входа, автоматизация обработки CAPTCHA ботами — про встраивание в более широкий бот-процесс, и параллельное решение нескольких CAPTCHA — более подробный разбор параллелизма, чем в сценарии 4.