Python에서 PopularCaptcha 푸는 방법 (동작하는 예제, 2026)
Python 스크립트가 PopularCaptcha에 막혔다면, 브라우저 팜이나 직접 만든 모델은 필요하지 않습니다. 필요한 것은 페이지의 sitekey, POST 요청 한 번, 그리고 돌아오는 토큰입니다.
이 가이드는 약 5분 안에 제로에서 동작하는 토큰까지 가게 해 줍니다. API 키를 받고, sitekey를 찾고, 토큰을 요청하고, 폼에 제출하고, 스크립트가 무인으로 돌 때 나타나는 실패 상황을 처리합니다. 실패한 풀이는 무료이므로, 재시도는 시간만 듭니다.
Scarnox는 오늘 PopularCaptcha를 프록시리스로 또는 자체 프록시와 함께 풉니다. reCAPTCHA, Cloudflare Turnstile, AWS WAF 같은 다른 captcha 유형은 출시 예정이므로, 여기 모든 예제는 PopularCaptcha를 사용합니다. 다른 유형이 어떻게 다른지는 captcha 유형 개요를 참고하세요.
1. API 키 받기
계정을 만들고 무료 체험 크레딧으로 카드 없이 시작하세요. API 키는 대시보드에 있습니다. 소스 코드에 넣지 말고, 환경 변수에서 읽으세요.
export SCARNOX_KEY="scarnox_YOURAPIKEY"
2. sitekey 찾기
captcha가 있는 페이지를 열고, DevTools를 연 뒤, Elements 패널에서 data-sitekey를 검색하세요. PopularCaptcha의 sitekey는 UUID입니다.
<div class="h-captcha" data-sitekey="10000000-ffff-ffff-ffff-000000000001"></div>
HTML에 data-sitekey가 없나요? 위젯은 아마 JavaScript로 렌더링된 것입니다. Network 탭에서 위젯의 설정 요청을 찾으세요. 필요한 것은 그 요청의 sitekey 쿼리 매개변수입니다. iframe URL과 보이지 않는 위젯을 포함한 다른 방법은 sitekey 찾는 다른 방법에서 다룹니다.
위젯을 보여 주는 페이지의 URL을 site_url로 보내세요. 호스트가 가장 중요하지만, 전체 페이지 URL이 안전한 선택입니다.
3. 토큰 요청하기
import os
import requests
API_URL = "https://api.scarnox.com/api/tasks/create"
API_KEY = os.environ["SCARNOX_KEY"]
def solve_captcha(sitekey: str, page_url: str) -> str:
r = requests.post(
API_URL,
headers={"Authorization": f"Bearer {API_KEY}"},
json={
"captcha_type": "PopularCaptchaTaskProxyless",
"site_key": sitekey,
"site_url": page_url,
},
timeout=185, # 토큰이 준비될 때까지 호출이 블로킹됩니다
)
data = r.json()
if data.get("errorId") != 0:
raise RuntimeError(f"{data.get('errorCode')}: {data.get('errorDescription')}")
return data["solution"]["token"]
if __name__ == "__main__":
token = solve_captcha("10000000-ffff-ffff-ffff-000000000001", "https://example.com/signup")
print(token[:40], "...")
통합은 이것이 전부입니다. 폴링 루프도, 두 번째 "결과 가져오기" 호출도 없습니다. 요청은 토큰이 준비되면 반환하므로, 중요한 설정은 느린 풀이를 감당할 만큼 긴 타임아웃 하나뿐입니다. 약 185초를 사용하세요.
성공 응답은 errorId가 0이고, 토큰은 solution.token에 있습니다. 다른 errorId는 풀이가 실패했다는 뜻이며, 응답에는 이유를 설명하는 errorCode와 errorDescription이 들어 있습니다.
4. 토큰 제출하기
토큰은 사이트가 captcha 응답을 기대하는 곳으로 가면 됩니다. PopularCaptcha의 경우 거의 항상 h-captcha-response라는 이름의 폼 필드입니다. 많은 사이트가 g-recaptcha-response도 받아들이므로, 둘 다 보내세요.
import requests
def sign_up(session: requests.Session, form_url: str, email: str, sitekey: str) -> requests.Response:
token = solve_captcha(sitekey, form_url)
return session.post(form_url, data={
"email": email,
"h-captcha-response": token,
"g-recaptcha-response": token,
}, timeout=30)
여기서 중요한 세부 사항은 두 가지입니다. 실제 사이트는 보통 페이지 로드 때의 세션 쿠키도 확인하므로, POST 전에 같은 requests.Session으로 폼을 불러오세요. 그리고 POST는 페이지 URL이 아니라 폼의 action URL로 보내세요. 둘이 항상 같지는 않습니다.
제출 직전에 풀이하세요. 토큰은 약 2분 안에 만료되므로, 긴 작업을 시작할 때 미리 가져와서 들고 있지 마세요. 사이트가 토큰을 거부하면, DevTools에서 폼을 열고 숨겨진 필드 이름이 맞는지 확인하세요.
5. 실패 처리하기
실패한 풀이는 무료이므로, 재시도는 시간 말고는 비용이 없습니다. 하지만 어떤 오류는 재시도해도 절대 성공하지 않으므로, 무턱대고 반복하지 마세요. 매번 errorId를 확인하고, errorCode와 errorDescription을 기록하고, 일시적인 실패만 재시도하세요.
네트워크 오류는 별도로 처리해야 합니다. requests는 응답이 생기기 전에 예외를 던지기 때문입니다.
import requests
try:
token = solve_captcha(sitekey, page_url)
except requests.RequestException as exc:
print("network problem, retry later:", exc)
except RuntimeError as exc:
print("solve rejected:", exc)
백오프와 지터를 포함한 완전한 재시도 정책은 오류 처리 가이드에 있습니다.
흔한 실수
- **잘못된
site_url.** 홈페이지가 아니라 위젯을 표시하는 페이지를 보내세요. - 오래된 토큰. 약 2분이 지나 쓴 토큰은 거부됩니다. 제출 직전에 풀이하세요.
- 세션 누락. 페이지의 쿠키 없이 보낸 POST는 토큰이 유효해도 실패할 수 있습니다.
- **일부 사이트는
rqdata가 필요합니다.** 페이지가 위젯용rqdata값을 제공한다면, 선택 필드인rqdata로 요청에 넘기세요. - 보이지 않는 위젯. 체크박스가 없고 사이트가 자체 코드에서 위젯을 시작한다면, 요청에
"is_invisible": true를 추가하세요. 보이지 않는 captcha 가이드가 토큰을 돌려주는 방법을 보여 줍니다.
무료로 체험하기
계정을 만들고 무료 체험 크레딧으로 카드 없이 시작하세요. 더 큰 작업에 연결하기 전에, 위 예제를 직접 소유한 폼에서 먼저 실행하세요. 대량 풀이의 비용은 현재 요금을 확인하세요.
풀이마다 로그 남기기
풀이 한 번마다 로그 한 줄을 남기세요. sitekey, 페이지 호스트, errorId, 실패 시 errorCode, 호출에 걸린 시간을 기록합니다. API 키와 프록시 비밀번호는 빼세요. 이 줄들을 보면, 실행이 느린 이유가 페이지 때문인지, 프록시 때문인지, 솔버 때문인지 알 수 있습니다. 지원 요청을 열 때 가장 먼저 필요한 것이기도 합니다.
루프에서 풀기
스크립트가 captcha를 연달아 많이 푼다면, 루프는 단순하게 유지하세요. 풀고, 제출하고, 결과를 확인한 뒤에야 다음으로 넘어가세요. 미리 풀어서 토큰을 대기열에 쌓지 마세요. 각 토큰은 약 2분 안에 만료됩니다. 같은 사이트에 대한 풀이 사이에 짧은 간격을 두면, 요청 빈도가 사람이 만들어 낼 수준에 가깝게 유지됩니다.