# การคลิกภาพ reCAPTCHA v2 ด้วย Selenium

> ใช้ Python, Selenium 4 และ ReCaptchaV2Classification เพื่อคลิกโจทย์ภาพของ reCAPTCHA v2 ในเบราว์เซอร์จริง ตั้งแต่เรียกให้ CAPTCHA แสดง อ่านคำถามและภาพ เรียก API คลิกช่อง จนถึงส่งฟอร์ม พร้อมโค้ดตัวอย่างฉบับสมบูรณ์

Source: https://docs.yescaptcha.com/th/guides/recaptcha-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/recaptcha-click-selenium/

บทช่วยสอนนี้ใช้ Selenium 4 เปิดหน้าเดโมของ reCAPTCHA จาก Google แล้วทำโจทย์ภาพให้เสร็จในเบราว์เซอร์จริง โดยอ่านคำถามและภาพ ส่งให้ [reCAPTCHA v2 การจดจำภาพ](https://docs.yescaptcha.com/th/tasks/recaptcha-classification.md) (`ReCaptchaV2Classification`) ตัดสินว่าควรคลิกช่องใดบ้าง แล้วจำลองการคลิก เมื่อเทียบกับวิธีขอ token วิธีนี้ผ่านการตรวจสอบในเบราว์เซอร์จริง เหมาะกับเว็บไซต์ที่ token ผ่านได้ยาก

หากไม่ต้องการเขียนโค้ด สามารถใช้ [ส่วนขยายเบราว์เซอร์](https://docs.yescaptcha.com/th/extension.md) ได้เลย เพราะทำงานด้วยการคลิกอัตโนมัติผ่าน API เดียวกัน

## การเตรียมตัว

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

ต้องติดตั้ง Chrome โดย Selenium 4 จะดาวน์โหลด chromedriver ที่ตรงกันให้อัตโนมัติ

## ขั้นตอน

1.  **คลิกช่องกาเครื่องหมาย** ช่องนี้อยู่ใน iframe ที่มี `title="reCAPTCHA"` ให้สลับเข้าไปก่อน แล้วคลิก `#recaptcha-anchor`
2.  **สลับไปยัง iframe ของโจทย์** โจทย์อยู่ใน iframe อีกตัวที่ title มีคำว่า “challenge”
3.  **อ่านคำถาม** ข้อความตัวหนาใน `.rc-imageselect-desc-wrapper strong` คือสิ่งที่ต้องหา เช่น “traffic lights” API ต้องใช้ ID ของคำถาม จึงต้องแปลงชื่อเป็น ID (`/m/015qff`) ด้วยตารางเทียบ ดู [ID ของคำถาม](https://docs.yescaptcha.com/th/tasks/recaptcha-classification.md) หน้าจอเบราว์เซอร์ภาษาอังกฤษจะเทียบได้สะดวกที่สุด
4.  **ดึงภาพ** ภาพในแต่ละช่องจริง ๆ แล้วเป็นภาพใหญ่ภาพเดียวกัน ให้ดาวน์โหลดจาก `src` ของ `td.rc-imageselect-tile img` สำหรับ 9 ช่อง (3x3) ปรับขนาดเป็น 300×300 และสำหรับ 16 ช่อง (4x4) ปรับเป็น 450×450 แล้วแปลงเป็น Base64
5.  **จดจำภาพ** เรียก `createTask` ด้วยประเภทงาน `ReCaptchaV2Classification` และส่ง `image` กับ `question` เพิ่ม `"confidence": 0.5` แล้วภาพ 3x3 จะคืนทุกช่องที่ตรงเงื่อนไขในครั้งเดียว ไม่ต้องจัดการกับภาพเล็กที่โหลดใหม่หลังคลิก
6.  **คลิก** `objects` ที่คืนมาคือลำดับของช่อง เริ่มจาก 0 เรียงจากซ้ายไปขวาและบนลงล่าง ให้คลิก `td` ที่ตรงกันตามลำดับ
7.  **ยืนยัน** คลิก `#recaptcha-verify-button` หากมีโจทย์รอบใหม่ขึ้นมาอีก ให้กลับไปขั้นตอนที่ 3 เมื่อหน้าต่างโจทย์ปิดไปแสดงว่าผ่านแล้ว
8.  **ส่งฟอร์ม** กลับมาที่หน้าหลักแล้วคลิกปุ่มส่ง

## โค้ดฉบับสมบูรณ์

recaptcha_click_selenium.py

```python
"""Click through a reCAPTCHA v2 image challenge with Selenium 4 and ReCaptchaV2Classification.

Flow: open the page -> click the checkbox -> read the target name and the grid image ->
ask YesCaptcha which tiles to click -> click them -> press Verify. Repeat if a new challenge appears.

Run:  pip install requests selenium pillow
      export YESCAPTCHA_CLIENT_KEY=your_client_key
      python recaptcha_click_selenium.py
Each recognized image is charged (see the price list). reCAPTCHA's page structure can change;
adjust the selectors below if a step stops working.
"""
import base64
import io
import os
import time

import requests
from PIL import Image
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://www.google.com/recaptcha/api2/demo"

# Target names shown in the challenge (English UI) -> question IDs.
# Full list: https://docs.yescaptcha.com/en/tasks/recaptcha-classification/
QUESTION_IDS = {
    "taxis": "/m/0pg52", "bus": "/m/01bjv", "buses": "/m/01bjv", "motorcycles": "/m/04_sv",
    "tractors": "/m/013xlm", "chimneys": "/m/01jk_4", "crosswalks": "/m/014xcs",
    "traffic lights": "/m/015qff", "bicycles": "/m/0199g", "parking meters": "/m/015qbp",
    "cars": "/m/0k4j", "bridges": "/m/015kr", "boats": "/m/019jd", "palm trees": "/m/0cdl1",
    "mountains or hills": "/m/09d_r", "fire hydrants": "/m/01pns0", "a fire hydrant": "/m/01pns0",
    "stairs": "/m/01lynh",
}

def classify(image_b64, question):
    task = {"type": "ReCaptchaV2Classification", "image": image_b64, "question": question, "confidence": 0.5}
    data = requests.post(
        "https://api.yescaptcha.com/createTask",
        json={"clientKey": CLIENT_KEY, "task": task},
        timeout=30,
    ).json()
    if data.get("errorId"):
        raise RuntimeError(f"{data.get('errorCode')}: {data.get('errorDescription')}")
    return data["solution"]  # synchronous: the solution comes back right away

def grid_image_b64(url, size):
    """Download the challenge image and scale it to the standard size (300 for 3x3, 450 for 4x4)."""
    img = Image.open(io.BytesIO(requests.get(url, timeout=30).content)).convert("RGB")
    img = img.resize((size, size))
    buf = io.BytesIO()
    img.save(buf, format="JPEG")
    return base64.b64encode(buf.getvalue()).decode()

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

    # 1. Click the checkbox (inside the "reCAPTCHA" iframe)
    wait.until(EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR, 'iframe[title="reCAPTCHA"]')))
    wait.until(EC.element_to_be_clickable((By.ID, "recaptcha-anchor"))).click()
    driver.switch_to.default_content()

    # 2. Switch to the challenge iframe and solve rounds until it closes
    wait.until(EC.frame_to_be_available_and_switch_to_it(
        (By.XPATH, '//iframe[contains(@title, "challenge")]')))
    for _ in range(5):
        target = wait.until(EC.presence_of_element_located(
            (By.CSS_SELECTOR, ".rc-imageselect-desc-wrapper strong"))).text.strip().lower()
        question = QUESTION_IDS.get(target)
        if not question:
            print("unsupported target, reloading:", target)
            driver.find_element(By.ID, "recaptcha-reload-button").click()
            time.sleep(2)
            continue
        tiles = driver.find_elements(By.CSS_SELECTOR, "td.rc-imageselect-tile")
        size = 450 if len(tiles) == 16 else 300
        url = driver.find_element(By.CSS_SELECTOR, "td.rc-imageselect-tile img").get_attribute("src")
        solution = classify(grid_image_b64(url, size), question)
        for index in solution.get("objects", []):
            tiles[index].click()
            time.sleep(0.3)
        time.sleep(1)
        driver.find_element(By.ID, "recaptcha-verify-button").click()
        time.sleep(3)
        driver.switch_to.default_content()
        frame = driver.find_element(By.XPATH, '//iframe[contains(@title, "challenge")]')
        if not frame.is_displayed():  # challenge closed: passed
            break
        driver.switch_to.frame(frame)

    driver.switch_to.default_content()
    driver.find_element(By.ID, "recaptcha-demo-submit").click()
    time.sleep(2)
    print("passed" if "Verification Success" in driver.page_source else "not passed")
finally:
    driver.quit()
```

## หมายเหตุ

-   โครงสร้างหน้าเว็บของ reCAPTCHA มีการอัปเดตอยู่เสมอ หาก selector ในโค้ดใช้ไม่ได้ ให้ปรับตามหน้าเว็บจริง
-   การจดจำภาพทุกครั้งจะหักพอยต์ (ดูราคาได้ที่ [reCAPTCHA v2 การจดจำภาพ](https://docs.yescaptcha.com/th/tasks/recaptcha-classification.md)) งานที่คลิกแล้วยืนยันไม่ผ่านสามารถ [รายงาน](https://docs.yescaptcha.com/th/api/report.md) ภายใน 1 ชั่วโมงเพื่อขอคืนพอยต์หลังรายงานได้
-   หากพบคำถามที่ไม่มีในตารางเทียบ ให้คลิกปุ่มรีเฟรชเพื่อเปลี่ยนโจทย์ หรือติดต่อฝ่ายสนับสนุนเพื่อขอให้เพิ่มการรองรับ
