# hCaptcha 이미지 인식 클릭 시뮬레이션(Selenium)

> Python Selenium 4와 HCaptchaClassification으로 브라우저에서 hCaptcha의 3×3 그리드 이미지 문제를 자동으로 풀어요. 체크박스 클릭, 질문과 이미지 9장 읽기, 인식 API 호출, 클릭, 제출까지 전체 예제 코드를 제공해요.

Source: https://docs.yescaptcha.com/ko/guides/hcaptcha-click-selenium/ · Last verified: 2026-10-15

> This page was machine-translated from the Chinese version. If anything differs, the Chinese version prevails: https://docs.yescaptcha.com/zh/guides/hcaptcha-click-selenium/

이 튜토리얼은 Selenium 4로 hCaptcha 데모 페이지를 열고, 실제 브라우저에서 3×3 그리드 이미지 문제를 풀어요. 질문과 이미지 9장을 읽은 뒤 [hCaptcha 이미지 인식](https://docs.yescaptcha.com/ko/tasks/hcaptcha-classification.md)(`HCaptchaClassification`)에 보내 어떤 칸이 목표인지 판단하게 하고, 그 칸을 클릭해요.

hCaptcha에는 “지정한 위치 클릭”, “드래그” 같은 문제 유형도 있어요. 이런 유형은 칸이 아니라 좌표를 반환해요. 처리 방법은 [hCaptcha 이미지 인식](https://docs.yescaptcha.com/ko/tasks/hcaptcha-classification.md)을 참고하세요. 코드를 작성하고 싶지 않다면 [브라우저 확장 프로그램](https://docs.yescaptcha.com/ko/extension.md)을 바로 사용하세요. 이 문제 유형을 모두 지원해요.

## 준비

```bash
pip install requests selenium
export YESCAPTCHA_CLIENT_KEY=your_client_key
```

## 흐름

1.  **체크박스를 클릭해요.** 체크박스는 주소에 `frame=checkbox`가 포함된 hCaptcha iframe 안에 있어요. 해당 iframe으로 전환한 뒤 `#checkbox`를 클릭하세요.
2.  **문제 iframe으로 전환해요.** 문제는 주소에 `frame=challenge`가 포함된 iframe 안에 있어요.
3.  **질문을 읽어요.** `.prompt-text`의 텍스트가 질문이에요. 그대로 API에 전달하세요(hCaptcha 인터페이스 언어를 영어 또는 중국어 간체로 바꾸는 것을 권장해요). 질문 옆에 예시 이미지가 있으면 그 이미지도 `anchors`에 넣으세요.
4.  **이미지를 가져와요.** 각 칸 `.task-image .image`의 배경 이미지가 이미지 한 장이에요. 순서대로 다운로드해 Base64로 변환하고 `queries` 목록을 만드세요.
5.  **인식해요.** `createTask`를 호출하고 유형은 `HCaptchaClassification`으로 지정하세요. 반환된 `objects`는 칸과 하나씩 대응하고, `true`인 칸이 목표예요.
6.  **클릭하고 제출해요.** 목표인 칸을 클릭하고 제출 버튼을 누르세요. 여러 라운드가 연속으로 나올 수 있으니 3~6단계를 반복하세요.
7.  **완료해요.** 통과하면 페이지의 `h-captcha-response` 필드에 토큰이 들어가요. 이 토큰을 폼과 함께 제출하세요.

## 전체 코드

hcaptcha_click_selenium.py

```python
"""Click through an hCaptcha 3x3 image challenge with Selenium 4 and HCaptchaClassification.

Flow: open the page -> click the checkbox -> read the question and the 9 images ->
ask YesCaptcha which images match -> click them -> submit. Repeat while new rounds appear.

Run:  pip install requests selenium
      export YESCAPTCHA_CLIENT_KEY=your_client_key
      python hcaptcha_click_selenium.py
Each recognized round is charged (see the price list; rounds with no target found are free).
hCaptcha changes its page structure often; adjust the selectors below if a step stops working.
Click and drag questions return coordinates instead; see the HCaptchaClassification page.
"""
import base64
import os
import re
import time

import requests
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait

CLIENT_KEY = os.environ["YESCAPTCHA_CLIENT_KEY"]
PAGE_URL = "https://accounts.hcaptcha.com/demo"

def classify(question, images_b64):
    task = {"type": "HCaptchaClassification", "question": question, "queries": images_b64}
    data = requests.post(
        "https://api.yescaptcha.com/createTask",
        json={"clientKey": CLIENT_KEY, "task": task},
        timeout=60,
    ).json()
    if data.get("errorId"):
        raise RuntimeError(f"{data.get('errorCode')}: {data.get('errorDescription')}")
    return data["solution"]  # synchronous

def background_image_b64(element):
    """The tiles are <div>s with a CSS background image; download it and Base64-encode it."""
    style = element.get_attribute("style") or ""
    match = re.search(r'url\("?(.*?)"?\)', style)
    if not match:
        return None
    return base64.b64encode(requests.get(match.group(1), timeout=30).content).decode()

driver = webdriver.Chrome()
wait = WebDriverWait(driver, 15)
try:
    driver.get(PAGE_URL)

    # 1. Click the checkbox (inside the first hCaptcha iframe)
    wait.until(EC.frame_to_be_available_and_switch_to_it(
        (By.CSS_SELECTOR, 'iframe[src*="hcaptcha"][src*="frame=checkbox"]')))
    wait.until(EC.element_to_be_clickable((By.ID, "checkbox"))).click()
    driver.switch_to.default_content()

    # 2. Solve rounds in the challenge iframe
    wait.until(EC.frame_to_be_available_and_switch_to_it(
        (By.CSS_SELECTOR, 'iframe[src*="hcaptcha"][src*="frame=challenge"]')))
    for _ in range(5):
        question = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, ".prompt-text"))).text.strip()
        tiles = driver.find_elements(By.CSS_SELECTOR, ".task-image")
        images = [background_image_b64(t.find_element(By.CSS_SELECTOR, ".image")) for t in tiles]
        if not tiles or None in images:
            print("not a 3x3 image challenge; see the docs for click/drag questions")
            break
        solution = classify(question, images)
        for tile, hit in zip(tiles, solution.get("objects", [])):
            if hit:
                tile.click()
                time.sleep(0.3)
        driver.find_element(By.CSS_SELECTOR, ".button-submit").click()
        time.sleep(3)
        if not driver.find_elements(By.CSS_SELECTOR, ".task-image"):
            break

    driver.switch_to.default_content()
    token = driver.find_element(By.NAME, "h-captcha-response").get_attribute("value")
    print("token received" if token else "not passed")
finally:
    driver.quit()
```

## 참고

-   hCaptcha의 페이지 구조는 자주 바뀌어요. 코드의 선택자가 동작하지 않으면 실제 페이지에 맞게 조정하세요.
-   라운드마다 포인트가 차감돼요. 목표를 인식하지 못한 라운드는 차감되지 않아요. 클릭 후 검증에 실패했다면 1시간 이내에 [신고](https://docs.yescaptcha.com/ko/api/report.md)해서 포인트 환불을 신청할 수 있어요.
-   새로운 질문에서 `ERROR_UNKNOWN_QUESTION`이 반환되면 새로고침해서 다른 문제를 받거나 고객 지원에 문의하세요.
