Меняются всего два значения — базовый URL и API-ключ, весь остальной формат запроса остаётся прежним: AZCaptcha и CaptchaAI используют один и тот же 2Captcha-совместимый API. Поэтому реальная миграция обычно занимает 15–30 минут на одну кодовую базу, а не переписывание интеграции с нуля. Ниже — готовый код на Python и Node.js «до/после», независимая от поставщика обёртка для быстрого отката, параллельный тест, а следом справочные таблицы по эндпоинтам и параметрам на случай, если что-то не совпадёт.
Пошаговый перенос интеграции
Четыре шага, в этом порядке: сначала ключ, затем код, затем обёртка для отката, и только потом — переключение трафика.
Шаг 1. Получите API-ключ CaptchaAI
- Зарегистрируйтесь на captchaai.com
- Пополните баланс аккаунта
- Скопируйте API-ключ из панели управления
Ключ понадобится в следующем шаге — сохраните его в переменную окружения, а не прямо в коде.
Шаг 2. Обновите код
Дальше — построчное сравнение старого и нового кода на Python и JavaScript.
Python — до (AZCaptcha)
import requests
API_KEY = "your_azcaptcha_key"
def solve_recaptcha(sitekey, pageurl):
# Submit
resp = requests.post("https://azcaptcha.com/in.php", data={
"key": API_KEY,
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": pageurl,
"json": 1
})
data = resp.json()
if data["status"] != 1:
return {"error": data["request"]}
captcha_id = data["request"]
# Poll
import time
for _ in range(60):
time.sleep(5)
result = requests.get("https://azcaptcha.com/res.php", params={
"key": API_KEY, "action": "get", "id": captcha_id, "json": 1
}).json()
if result["status"] == 1:
return {"solution": result["request"]}
if result["request"] != "CAPCHA_NOT_READY":
return {"error": result["request"]}
return {"error": "TIMEOUT"}
Python — после (CaptchaAI)
import os
import time
import requests
API_KEY = os.environ["CAPTCHAAI_API_KEY"] # Changed: use env var
def solve_recaptcha(sitekey, pageurl):
# Submit — only URL changed
resp = requests.post("https://ocr.captchaai.com/in.php", data={
"key": API_KEY,
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": pageurl,
"json": 1
})
data = resp.json()
if data.get("status") != 1:
return {"error": data.get("request")}
captcha_id = data["request"]
# Poll — only URL changed
for _ in range(60):
time.sleep(5)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY, "action": "get", "id": captcha_id, "json": 1
}).json()
if result.get("status") == 1:
return {"solution": result["request"]}
if result.get("request") != "CAPCHA_NOT_READY":
return {"error": result.get("request")}
return {"error": "TIMEOUT"}
Та же логика на JavaScript — тоже один URL меняется, остальное без правок:
JavaScript — до (AZCaptcha)
const axios = require("axios");
const API_KEY = "your_azcaptcha_key";
async function solveRecaptcha(sitekey, pageurl) {
const submit = await axios.post("https://azcaptcha.com/in.php", null, {
params: { key: API_KEY, method: "userrecaptcha", googlekey: sitekey, pageurl, json: 1 },
});
if (submit.data.status !== 1) return { error: submit.data.request };
const captchaId = submit.data.request;
for (let i = 0; i < 60; i++) {
await new Promise((r) => setTimeout(r, 5000));
const poll = await axios.get("https://azcaptcha.com/res.php", {
params: { key: API_KEY, action: "get", id: captchaId, json: 1 },
});
if (poll.data.status === 1) return { solution: poll.data.request };
if (poll.data.request !== "CAPCHA_NOT_READY") return { error: poll.data.request };
}
return { error: "TIMEOUT" };
}
JavaScript — после (CaptchaAI)
const axios = require("axios");
const API_KEY = process.env.CAPTCHAAI_API_KEY; // Changed: env var
async function solveRecaptcha(sitekey, pageurl) {
// Only URLs changed
const submit = await axios.post("https://ocr.captchaai.com/in.php", null, {
params: { key: API_KEY, method: "userrecaptcha", googlekey: sitekey, pageurl, json: 1 },
});
if (submit.data.status !== 1) return { error: submit.data.request };
const captchaId = submit.data.request;
for (let i = 0; i < 60; i++) {
await new Promise((r) => setTimeout(r, 5000));
const poll = await axios.get("https://ocr.captchaai.com/res.php", {
params: { key: API_KEY, action: "get", id: captchaId, json: 1 },
});
if (poll.data.status === 1) return { solution: poll.data.request };
if (poll.data.request !== "CAPCHA_NOT_READY") return { error: poll.data.request };
}
return { error: "TIMEOUT" };
}
Шаг 3. Абстрагируйте поставщика
Для безопасного отката оберните вызовы в независимый от поставщика класс — переключение сведётся к одной строке:
import os
import time
import requests
class CaptchaProvider:
def __init__(self, base_url, api_key):
self.submit_url = f"{base_url}/in.php"
self.result_url = f"{base_url}/res.php"
self.api_key = api_key
self.session = requests.Session()
def solve(self, sitekey, pageurl, method="userrecaptcha"):
resp = self.session.post(self.submit_url, data={
"key": self.api_key,
"method": method,
"googlekey": sitekey,
"pageurl": pageurl,
"json": 1
})
data = resp.json()
if data.get("status") != 1:
return {"error": data.get("request")}
captcha_id = data["request"]
for _ in range(60):
time.sleep(5)
result = self.session.get(self.result_url, params={
"key": self.api_key, "action": "get",
"id": captcha_id, "json": 1
}).json()
if result.get("status") == 1:
return {"solution": result["request"]}
if result.get("request") != "CAPCHA_NOT_READY":
return {"error": result.get("request")}
return {"error": "TIMEOUT"}
# Switch by changing one line:
# provider = CaptchaProvider("https://azcaptcha.com", "old_key")
provider = CaptchaProvider(
"https://ocr.captchaai.com",
os.environ["CAPTCHAAI_API_KEY"]
)
Теперь у вас есть единая точка переключения между поставщиками. Прежде чем менять продакшен, убедитесь на цифрах, что новый поставщик действительно быстрее и стабильнее — для этого нужен параллельный тест.
Шаг 4. Запустите оба поставщика параллельно
Перед переключением сравните оба поставщика на одинаковой нагрузке:
def parallel_test(sitekey, pageurl, runs=10):
azcaptcha = CaptchaProvider("https://azcaptcha.com", "old_key")
captchaai = CaptchaProvider(
"https://ocr.captchaai.com",
os.environ["CAPTCHAAI_API_KEY"]
)
results = {"azcaptcha": [], "captchaai": []}
for i in range(runs):
start = time.time()
az_result = azcaptcha.solve(sitekey, pageurl)
results["azcaptcha"].append({
"success": "solution" in az_result,
"time": time.time() - start
})
start = time.time()
cai_result = captchaai.solve(sitekey, pageurl)
results["captchaai"].append({
"success": "solution" in cai_result,
"time": time.time() - start
})
for provider, data in results.items():
successes = sum(1 for r in data if r["success"])
avg_time = sum(r["time"] for r in data) / len(data)
print(f"{provider}: {successes}/{runs} success, {avg_time:.1f}s avg")
Логи параллельного теста храните обезличенными — без sitekey реальных клиентских сайтов и без чужих cookie, особенно если команда отчитывается по 152-ФЗ «О персональных данных» или соблюдает GDPR для клиентов из ЕС.
Чем отличаются эндпоинты AZCaptcha и CaptchaAI
Как видно из кода выше, хост меняется, а пути — нет: in.php для отправки задачи и res.php для получения результата остаются теми же самыми путями. Полная таблица — на случай, если переносите не только reCAPTCHA, но и другие типы:
| Действие | AZCaptcha | CaptchaAI |
|---|---|---|
| Отправить задачу | https://azcaptcha.com/in.php |
https://ocr.captchaai.com/in.php |
| Получить результат | https://azcaptcha.com/res.php |
https://ocr.captchaai.com/res.php |
| Проверить баланс | res.php?action=getbalance |
res.php?action=getbalance |
| Сообщить о неверном решении | res.php?action=reportbad |
res.php?action=reportbad |
Что меняется в параметрах запроса
Почти все параметры совпадают один в один, и их можно перенести без изменений. Разница только в значении самого ключа:
| Параметр | AZCaptcha | CaptchaAI | Примечание |
|---|---|---|---|
key |
API-ключ | API-ключ | Другой ключ — получите свой на captchaai.com |
method |
userrecaptcha |
userrecaptcha |
Без изменений |
googlekey |
sitekey | sitekey | Без изменений |
pageurl |
URL страницы | URL страницы | Без изменений |
json |
1 |
1 |
Без изменений |
proxy |
user:pass@host:port |
user:pass@host:port |
Тот же формат |
proxytype |
HTTP/SOCKS5 |
HTTP/SOCKS5 |
Без изменений |
Сколько потоков брать вместо тарифа AZCaptcha
CaptchaAI тарифицирует не решения, а параллельные потоки, поэтому при переходе стоит ориентироваться на пиковую одновременную нагрузку, а не на суточный объём задач. Команда, которая держит около 10–15 одновременных задач reCAPTCHA v2, обычно укладывается в STANDARD ($30/мес, 15 потоков); при устойчивом пике в 40–50 задач разумнее сразу взять ADVANCE ($90/мес, 50 потоков). Для агентств и фрилансеров, которые выставляют счета клиентам в долларах, а не в местной валюте, это заодно и предсказуемая фиксированная строка в бюджете вместо плавающей цены за решение, которая зависит от курса.
Чек-лист миграции
Держите этот список рядом с тикетом на миграцию — он покрывает всё, от первого пополнения баланса до вывода старого ключа из эксплуатации:
| Шаг | Статус |
|---|---|
| Создать аккаунт CaptchaAI и пополнить баланс | ☐ |
| Заменить базовый URL во всех файлах | ☐ |
| Обновить API-ключ (через переменную окружения) | ☐ |
| Запустить параллельный тест (от 10 решений) | ☐ |
| Сравнить долю успешных решений | ☐ |
| Сравнить время решения | ☐ |
| Обновить мониторинг и алерты под новые эндпоинты | ☐ |
| Переключить продакшен-трафик | ☐ |
| Понаблюдать за метриками 24 часа | ☐ |
| Вывести ключ AZCaptcha из эксплуатации | ☐ |
Типичные ошибки при переносе
Если что-то из чек-листа выше не сходится, начните отсюда — это самые частые причины сбоя после переключения:
| Проблема | Причина | Решение |
|---|---|---|
ERROR_KEY_DOES_NOT_EXIST |
Неверный API-ключ | Проверьте API-ключ CaptchaAI в панели управления |
ERROR_ZERO_BALANCE |
На новом аккаунте нет средств | Пополните баланс на captchaai.com |
| Коды ошибок не совпадают один в один | У сервисов небольшие расхождения в кодах ошибок | Сопоставьте коды заранее — большинство совпадают напрямую |
| Доля успешных решений заметно отличается | У сервисов разные пулы солверов | Запустите от 50 тестовых решений — на 10 запусках разброс не показателен статистически |
Частые вопросы
Нужно ли переписывать логику опроса res.php?
Нет. Формат ответа, параметр action=get и код CAPCHA_NOT_READY идентичны AZCaptcha — меняется только базовый URL, сам цикл опроса переносится без изменений.
Сколько потоков CaptchaAI взять вместо текущего тарифа AZCaptcha?
Считайте по пиковой одновременной нагрузке, а не по суточному объёму задач: одна задача занимает один поток, а решений на поток — без ограничения. Ориентиры по планам приведены в разделе выше.
Заработает ли текущая настройка прокси после перехода?
Да, без изменений. CaptchaAI принимает те же параметры proxy и proxytype в том же формате user:pass@host:port — переписывать прокси-конфигурацию не нужно.
Сколько времени займёт вся миграция?
Для одной кодовой базы — обычно 15–30 минут: большая часть времени уходит на замену базового URL через поиск-и-замену и на запуск параллельного теста для проверки результата.