Skip to content

hCaptcha image clicking with Selenium

This guide opens hCaptcha’s demo page with Selenium 4 and completes the 3x3 image challenge in a real browser: it reads the question and the 9 images, asks hCaptcha image recognition (HCaptchaClassification) which ones are targets, and clicks them.

hCaptcha also has click-a-position and drag questions, which return coordinates instead of tiles; see hCaptcha image recognition. Without code, the browser extension handles all of them.

终端窗口
pip install requests selenium
export YESCAPTCHA_CLIENT_KEY=your_client_key
  1. Click the checkbox. It is inside the hCaptcha iframe whose URL contains frame=checkbox; switch into it and click #checkbox.
  2. Switch to the challenge iframe, whose URL contains frame=challenge.
  3. Read the question. The text in .prompt-text is the question; send it as is (switching hCaptcha’s language to English or Simplified Chinese is recommended). If example images appear next to the question, send them in anchors too.
  4. Get the images. Each tile’s .task-image .image has the picture as a background image; download them in order, Base64-encode them, and build the queries list.
  5. Recognize. Call createTask with type HCaptchaClassification. objects in the result corresponds to the tiles; true means target.
  6. Click and submit. Click the target tiles and press the submit button. Several rounds may follow; repeat steps 3 to 6.
  7. Done. After passing, the page’s h-captcha-response field holds the token, which is submitted with the form.
hcaptcha_click_selenium.py
"""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 changes its page structure often; adjust the selectors if a step stops working.
  • Each recognized round is charged; rounds with no target found are free. Rounds whose clicks were rejected can be reported within 1 hour for a refund.
  • If a new question returns ERROR_UNKNOWN_QUESTION, refresh for another challenge or contact support.