pythonselenium-webdriverrecaptchaselenium-grid

Unable to Solve ReCAPTCHA v2 with CapSolver (ReCaptchaV2Classification) – Always Returning False - Python


I'm trying to solve a ReCAPTCHA v2 challenge using CapSolver with the ReCaptchaV2Classification task type.

However, whenever I call the CapSolver API, the response is always false, and the images are not being selected, so the CAPTCHA is never solved.

I've followed the official documentation but still can't get it to work. Any help or guidance would be greatly appreciated.

import time
import base64
import requests
import os

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager


CAPSOLVER_API_KEY = 'CAP-0000'

# Basic PT → EN translator for reCAPTCHA questions
WORD_TRANSLATOR = {
    "ônibus": "/m/01bjv",                # bus
    "ônibus escolar": "/m/02yvhj",       # school bus
    "semáforos": "/m/015qff",            # traffic lights
    "faixas de pedestre": "/m/014xcs",   # crosswalks
    "carros": "/m/0k4j",                 # cars
    "motocicletas": "/m/04_sv",          # motorcycles
    "hidrante": "/m/01pns0",             # fire hydrant
    "placas de trânsito": "/m/015qbp",   # parking meters
    "escadas": "/m/01lynh",              # stairs
    "bicicletas": "/m/0199g",            # bicycles
    "tratores": "/m/013xlm",             # tractors
    "táxis": "/m/0pg52",                 # taxis
    "cruzamentos": "/m/015kr",           # bridges
    "barcos": "/m/019jd",                # boats
    "palmeiras": "/m/0cdl1",             # palm trees
    "montanhas": "/m/09d_r",             # mountains or hills
    "chaminés": "/m/01jk_4",             # chimneys
}

def translate_question(text):
    for pt, en in WORD_TRANSLATOR.items():
        if pt in text:
            return en
    return ""  # fallback

def launch_browser():
    options = Options()
    options.add_argument("--disable-blink-features=AutomationControlled")
    options.add_experimental_option("excludeSwitches", ["enable-automation"])
    options.add_argument("start-maximized")
    options.add_argument("--no-sandbox")
    options.add_argument("--disable-dev-shm-usage")
    options.add_experimental_option("detach", True)

    root_path = os.path.dirname(os.path.abspath(__file__))
    extension_path = os.path.join(root_path, "PGOJNOJMMHPOFJGDMAEBADHBOCAHPPOD_1_15_5_0.crx")
    options.add_extension(extension_path)

    driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=options)
    driver.set_page_load_timeout(60)
    return driver

def click_checkbox(driver):
    WebDriverWait(driver, 10).until(
        EC.frame_to_be_available_and_switch_to_it((By.XPATH, "//iframe[contains(@src, 'anchor')]"))
    )
    WebDriverWait(driver, 10).until(
        EC.element_to_be_clickable((By.ID, "recaptcha-anchor"))
    ).click()
    driver.switch_to.default_content()

def capture_question(driver):
    try:
        driver.switch_to.default_content()
        WebDriverWait(driver, 10).until(
            EC.frame_to_be_available_and_switch_to_it((By.XPATH, "//iframe[contains(@src, 'bframe')]"))
        )

        strong = WebDriverWait(driver, 5).until(
            EC.presence_of_element_located((By.CSS_SELECTOR, ".rc-imageselect-desc-wrapper strong"))
        )
        text = strong.text.strip().lower()
        print(f"🧠 Captured question: {text}")

        if "ônibus" in text:
            if "escolar" in text:
                return "/m/02yvhj"
            else:
                return "/m/01bjv"

        for pt, code in WORD_TRANSLATOR.items():
            if pt in text:
                print(f"🔎 Matched term: '{pt}' → code {code}")
                return code

        print("⚠️ No matching term found.")
        return ""

    except Exception as e:
        print("❌ Error capturing question:", e)
        return ""

def take_grid_screenshot(driver, path='grid.png'):
    try:
        driver.switch_to.default_content()
        WebDriverWait(driver, 10).until(
            EC.frame_to_be_available_and_switch_to_it((By.XPATH, "//iframe[contains(@src, 'bframe')]"))
        )

        grid_container = WebDriverWait(driver, 10).until(
            EC.presence_of_element_located((By.ID, "rc-imageselect-target"))
        )
        grid_container.screenshot(path)
        print(f"📸 Screenshot saved: {path}")

    except Exception as e:
        print(f"❌ Error taking grid screenshot: {e}")
        raise

def image_to_base64(path):
    with open(path, 'rb') as img:
        return base64.b64encode(img.read()).decode('utf-8')

def solve_with_capsolver(image_b64, question_en):
    url = "https://api.capsolver.com/createTask"
    print('question:', question_en)
    payload = {
        "clientKey": CAPSOLVER_API_KEY,
        "task": {
            "type": "ReCaptchaV2Classification",
            "image": image_b64,
            "question": question_en
        }
    }
    response = requests.post(url, json=payload)
    result = response.json()
    print(f"📬 CapSolver response: {result}")
    solution = result.get('solution', {})
    return solution.get('objects', []), solution.get('hasObject', False)

def click_images(driver, indices):
    images = driver.find_elements(By.CSS_SELECTOR, "td img")
    print(f"Images found: {len(images)} - clicking indices: {indices}")
    tds = driver.find_elements(By.CSS_SELECTOR, "table.rc-imageselect-table td")
    for i in indices:
        if i < len(tds):
            try:
                tds[i].click()
                time.sleep(0.4)
            except:
                pass

def is_challenge_active(driver):
    try:
        return driver.find_element(By.CSS_SELECTOR, "div.rc-imageselect") is not None
    except:
        return False

def solve_recaptcha(driver):
    driver.get("https://www.google.com/recaptcha/api2/demo")
    click_checkbox(driver)

    attempt = 1
    while True:
        print(f"[{attempt}] Attempting to solve challenge...")

        try:
            question_en = capture_question(driver)
            if not question_en:
                print("❌ Invalid or unrecognized question.")
                break

            take_grid_screenshot(driver, 'grid.png')
            base64_img = image_to_base64('grid.png')
            indices, has_object = solve_with_capsolver(base64_img, question_en)

            images = driver.find_elements(By.CSS_SELECTOR, "td img")
            print(f"Images found: {len(images)}")

            if len(images) > 9:
                print("⚠️ Grid with more than 9 images detected. Reloading.")
                driver.find_element(By.ID, "recaptcha-reload-button").click()
                time.sleep(2)
                attempt += 1
                continue

            if not has_object:
                print("🤖 No object detected. Clicking 'Skip' and retrying.")
                driver.find_element(By.ID, "recaptcha-reload-button").click()
                time.sleep(2)
                attempt += 1
                continue

            click_images(driver, indices)

            try:
                verify_btn = WebDriverWait(driver, 2).until(
                    EC.element_to_be_clickable((By.ID, "recaptcha-verify-button"))
                )
                verify_btn.click()
                print("🟢 'Verify' button clicked.")
            except:
                print("🔄 'Verify' button not visible yet.")

            time.sleep(3)

            driver.switch_to.default_content()
            WebDriverWait(driver, 10).until(
                EC.frame_to_be_available_and_switch_to_it((By.XPATH, "//iframe[contains(@src, 'bframe')]"))
            )

            if not is_challenge_active(driver):
                print("✅ reCAPTCHA solved successfully!")
                break

        except Exception as e:
            print(f"❌ Error during solving process: {e}")
            break

        attempt += 1
        time.sleep(1)

def main():
    driver = launch_browser()
    solve_recaptcha(driver)

if __name__ == "__main__":
    main()

📬 CapSolver response: {'errorId': 0, 'status': 'ready', 'solution': {'hasObject': False, 'size': 0, 'type': ''}, 'taskId': '<task_id>'}

Solution

  • I managed to solve it by downloading the Google Chrome extension and adding the method that starts the chromedriver

    https://github.com/capsolver/capsolver-browser-extension