Решайте и отправляйте reCAPTCHA с aiohttp
Используйте aiohttp для прямой работы с REST API: создайте одну задачу, опрашивайте её до готовности, затем отправьте solution.token целевому сайту. Выполняйте запросы к API и целевому сайту в отдельных сессиях, чтобы Bearer-токен рабочего пространства никогда не попал на целевой сайт.
Для примера требуется Python 3.11+; создание, опрос и отправка целевому сайту ограничены общим временем в 180 секунд. Это тайм-аут приложения, а не гарантированное время решения.
На этой странице
Задайте сайт, прокси и целевой запрос
- Задайте для SOLVETHREE_API_KEY API-ключ рабочего пространства. Храните его на сервере.
- Задайте для SOLVETHREE_PROXY URL прокси, который сервис должен использовать для решения CAPTCHA. Отправка целевому сайту выполняется через тот же прокси.
- Замените accounts.example.com и действие login именем хоста и действием, используемыми в вашей интеграции. Для сайта нужен активный профиль, доступный вашему рабочему пространству; настройте профиль перед созданием задач.
- Замените URL входа на целевой сайт и данные формы фактическим запросом приложения. Пример отправляет только g-recaptcha-response; добавьте остальные поля, необходимые целевому сайту, и используйте ожидаемое им поле токена.
Задача передаёт site, action и один proxy. По умолчанию используется reCAPTCHA Enterprise v3; не добавляйте поля type или url. Если целевому процессу нужны cookies из предыдущего запроса, выполняйте эти запросы через сессию целевого сайта — пример начинает с новой сессии.
Создайте задачу один раз, опросите её и отправьте токен
# pip install aiohttp
import asyncio
import os
import uuid
from urllib.parse import urlsplit, unquote
import aiohttp
async def main():
api = "https://api.solvethree.com/v1"
proxy = os.environ["SOLVETHREE_PROXY"]
task = {"site": "accounts.example.com", "action": "login", "proxy": proxy, "requestId": str(uuid.uuid4())}
task_id = None
try:
async with asyncio.timeout(180):
async with aiohttp.ClientSession(headers={"Authorization": "Bearer " + os.environ["SOLVETHREE_API_KEY"]}) as client:
async with client.post(api + "/tasks", params={"waitMs": 0}, json=task, allow_redirects=False) as response:
response.raise_for_status()
if response.status >= 300: raise RuntimeError("Unexpected API redirect")
result = await response.json()
task_id = result["id"]
while result["status"] in ("pending", "solving"):
async with client.get(api + "/tasks/" + task_id, params={"waitMs": 15000}, allow_redirects=False) as response:
response.raise_for_status()
if response.status >= 300: raise RuntimeError("Unexpected API redirect")
result = await response.json()
if result["status"] in ("pending", "solving"): await asyncio.sleep(1)
if result["status"] != "ready":
raise RuntimeError("Task failed: " + str(result.get("errorCode", "unknown")))
solution = result["solution"]
# A separate session prevents the API Bearer header reaching the target.
proxy_url = urlsplit(proxy)
netloc = proxy_url.netloc.rsplit("@", 1)[-1]
server = f"{proxy_url.scheme}://{netloc}"
auth = aiohttp.BasicAuth(unquote(proxy_url.username), unquote(proxy_url.password or "")) if proxy_url.username else None
async with aiohttp.ClientSession() as target:
async with target.post("https://accounts.example.com/login", proxy=server, proxy_auth=auth,
headers={"User-Agent": solution["userAgent"], "sec-ch-ua": solution["secChUa"]},
data={"g-recaptcha-response": solution["token"]}, allow_redirects=False) as response:
print("Application HTTP status:", response.status)
except TimeoutError:
print("Timed out; recover requestId", task["requestId"], "taskId", task_id)
raise
asyncio.run(main())Это прямая асинхронная работа с REST, а не асинхронный метод официального Python SDK. Пример выполняет один POST-запрос создания к /v1/tasks, сохраняет возвращённый id и использует GET-запросы для опроса этой задачи. Статусы pending и solving продолжают цикл; ready разрешает отправку; задача со статусом failed останавливает цикл.
Поле proxy в теле задачи указывает solvethree, какой прокси использовать. Аргументы aiohttp proxy и proxy_auth задаются только в HTTP-вызове целевого сайта, а не в вызовах API. Пример отделяет учётные данные прокси от URL прокси-сервера и отправляет токен с возвращёнными userAgent и secChUa.
Сессии намеренно разделены: заголовок Authorization есть только у сессии API. Перенаправления отключены, а перенаправления API считаются ошибками и не выполняются.
- Запрос к API возвращает HTTP-ошибку.
Пример проверяет HTTP-статус перед чтением данных успешного ответа.
Попробуйте: Обрабатывайте HTTP-ошибку отдельно от сбоя задачи. Перед повторной попыткой исправьте некорректные входные данные или проблемы авторизации.
- Задача переходит в статус failed.
Проверьте errorCode и error в ответе задачи. Пример выбрасывает исключение только с errorCode.
Попробуйте: Прекратите опрос этой задачи и устраните указанную причину. Исправьте указанную причину перед повторной попыткой.
- Задача готова, но приложение отклоняет запрос.
Проверьте отправляемое поле токена, целевой URL, возвращённые параметры браузера и прокси, а также все необходимые поля формы и cookies.
Попробуйте: Отправьте solution.token с возвращёнными параметрами браузера через тот же прокси. Оценивайте ответ приложения по критериям успеха целевого сайта — одного выведенного HTTP-статуса недостаточно, чтобы подтвердить принятие запроса.
Восстановление после тайм-аута без оплаты ещё одного решения
Тайм-аут при создании не доказывает, что создание завершилось неудачно. Пример сохраняет исходные входные данные в task и при истечении отведённого времени выводит его requestId и task_id. Эти переменные сохраняются только во время работы процесса; выведенные ID не составляют полной записи для восстановления.
- 1.
Сохраните исходный запрос перед созданием
Для восстановления после перезапусков надёжно сохраняйте полное тело задачи, включая requestId и proxy. Пример генерирует новый UUID при каждом запуске, поэтому простой повторный запуск создаёт новый логический запрос.
- 2.
Возобновите работу с существующей задачей
Если у вас есть task_id, получите эту задачу. Если при создании произошёл тайм-аут до получения ID, повторите создание с сохранёнными неизменёнными телом задачи и requestId. API вернёт существующую задачу; изменение входных данных при повторном использовании ID вызывает конфликт.
- 3.
Проверьте, не была ли отправка уже выполнена
Общее ограничение времени распространяется и на POST-запрос целевому сайту. Если этот запрос завершился по тайм-ауту, перед повторной отправкой проверьте результат в приложении: оно могло получить запрос, даже если ваш клиент не получил ответ. Восстановление задачи solvethree не позволяет определить, что произошло на целевом сайте.
Источники и справочник API
Запустите первую задачу.
Начните с $5 на балансе рабочего пространства.