aiohttp로 reCAPTCHA 해결 및 제출하기

작성: solvethree읽는 데 3분

aiohttp로 REST API를 직접 호출하세요. 작업 하나를 생성하고 준비될 때까지 폴링한 다음, solution.token을 대상에 제출하세요. 워크스페이스 Bearer 토큰이 대상에 전달되지 않도록 API 요청과 대상 요청을 별도의 세션으로 분리하세요.

이 예제에는 Python 3.11+가 필요하며, 생성, 폴링, 대상 제출 전체에 하나의 180초 제한 시간을 적용합니다. 이는 애플리케이션의 시간 제한이지 보장된 풀이 시간이 아닙니다.

이 페이지의 내용

사이트, 프록시, 대상 요청 설정

  • SOLVETHREE_API_KEY를 워크스페이스 API 키로 설정하세요. 키는 서버에 보관하세요.
  • SOLVETHREE_PROXY를 서비스가 풀이에 사용할 프록시 URL로 설정하세요. 대상 제출에도 동일한 프록시를 사용합니다.
  • accounts.example.com과 login 작업을 연동에 사용하는 호스트 이름과 작업으로 바꾸세요. 사이트에는 워크스페이스에서 사용할 수 있는 활성 프로필이 필요합니다. 작업을 생성하기 전에 프로필을 설정하세요.
  • 대상 로그인 URL과 폼 데이터를 실제 애플리케이션 요청으로 바꾸세요. 이 예제는 g-recaptcha-response만 전송합니다. 대상에 필요한 다른 필드를 추가하고 대상이 기대하는 토큰 필드를 사용하세요.

작업은 site, action, 단일 proxy를 전송합니다. 기본값은 reCAPTCHA Enterprise v3이며, type이나 url 필드를 추가하면 안 됩니다. 대상 흐름에 이전 요청의 쿠키가 필요하다면 대상 세션을 통해 해당 요청들을 보내세요. 이 예제는 새 세션으로 시작합니다.

한 번 생성하고 폴링한 뒤 제출

aiohttp · 한 번 생성한 뒤 폴링 및 제출
# 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())

이는 공식 Python SDK의 비동기 메서드가 아니라 직접 호출하는 비동기 REST 방식입니다. /v1/tasks에 생성 POST 요청을 한 번 보내고, 반환된 id를 저장한 다음, GET 요청으로 해당 작업을 폴링합니다. pending과 solving이면 반복을 계속하고, ready이면 제출할 수 있으며, 작업이 failed이면 반복을 중단합니다.

작업 본문의 proxy는 solvethree가 사용할 프록시를 지정합니다. aiohttp의 proxy와 proxy_auth 인수는 API 호출이 아니라 대상 HTTP 호출에만 사용됩니다. 이 예제는 프록시 자격 증명을 프록시 서버 URL과 분리하고, 반환된 userAgent 및 secChUa와 함께 토큰을 제출합니다.

세션은 의도적으로 분리되어 있으며, API 세션에만 Authorization 헤더가 있습니다. 리디렉션은 비활성화되어 있고, API 리디렉션은 따라가지 않고 오류로 처리합니다.

API 요청이 HTTP 오류를 반환합니다.

이 예제는 성공 페이로드를 읽기 전에 HTTP 상태를 확인합니다.

다음을 시도해 보세요: HTTP 오류는 작업 실패와 별도로 처리하세요. 재시도하기 전에 잘못된 입력이나 인증 문제를 수정하세요.

작업이 failed 상태가 됩니다.

작업 응답의 errorCode와 error를 확인하세요. 이 예제는 errorCode만 포함해 예외를 발생시킵니다.

다음을 시도해 보세요: 해당 작업의 폴링을 중단하고 보고된 원인을 처리하세요. 다시 시도하기 전에 보고된 원인을 해결하세요.

작업은 ready 상태이지만 애플리케이션이 요청을 거부합니다.

전송하는 토큰 필드, 대상 URL, 반환된 브라우저 식별 정보와 프록시, 필요한 폼 필드나 쿠키를 확인하세요.

다음을 시도해 보세요: 동일한 프록시를 통해 반환된 식별 정보와 함께 solution.token을 제출하세요. 대상의 성공 기준에 따라 애플리케이션 응답을 확인하세요. 출력된 HTTP 상태만으로는 수락 여부를 알 수 없습니다.

풀이를 추가 구매하지 않고 시간 초과 복구

생성 요청의 시간 초과가 생성 실패를 의미하지는 않습니다. 이 예제는 원래 입력을 task에 유지하고 제한 시간이 지나면 requestId와 task_id를 출력합니다. 이 변수들은 프로세스가 실행 중일 때만 유지되며, 출력된 ID만으로는 완전한 복구 기록이 되지 않습니다.

  1. 1.

    생성 전에 원래 요청 저장

    재시작 후에도 복구하려면 requestId와 proxy를 포함한 전체 작업 본문을 안전하게 보관하세요. 이 예제는 실행할 때마다 새 UUID를 생성하므로, 단순히 다시 실행하면 새로운 논리적 요청이 생성됩니다.

  2. 2.

    기존 작업 재개

    task_id가 있다면 해당 작업을 조회하세요. ID를 받기 전에 생성 요청이 시간 초과되었다면, 저장해 둔 작업 본문과 requestId를 변경하지 않고 생성 요청을 반복하세요. API는 기존 작업을 반환합니다. 같은 ID를 재사용하면서 입력을 변경하면 충돌이 발생합니다.

  3. 3.

    이미 제출되었는지 확인

    제한 시간에는 대상 POST 요청도 포함됩니다. 해당 요청이 시간 초과되었다면 다시 제출하기 전에 애플리케이션의 처리 결과를 확인하세요. 클라이언트가 응답을 받지 못했더라도 애플리케이션은 요청을 받았을 수 있습니다. solvethree 작업을 복구해도 대상에서 무슨 일이 있었는지는 알 수 없습니다.

첫 작업을 실행하세요.

워크스페이스 크레딧 $5로 시작하세요.

워크스페이스 만들기
aiohttp로 reCAPTCHA 해결 및 제출하기 · solvethree