Selenium занимается автоматизацией браузера; CaptchaAI занимается решением CAPTCHA. Вместе они решают наиболее распространенную проблему автоматизации — страницы, требующие как выполнения JavaScript, так и завершения CAPTCHA. В этом руководстве описан полный шаблон интеграции для reCAPTCHA v2/v3, Cloudflare Turnstile и графических CAPTCHA.
Предварительные условия
pip install selenium requests webdriver-manager
Настройка: Selenium в скрытой конфигурации
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
def create_driver():
"""Create a Selenium driver with стандартная конфигурация браузера-configuredion settings."""
options = webdriver.ChromeOptions()
options.add_argument("--disable-blink-features=AutomationControlled")
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option("useAutomationExtension", False)
driver = webdriver.Chrome(
service=Service(ChromeDriverManager().install()),
options=options,
)
# Remove webdriver flag
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
"source": "Object.defineProperty(navigator, 'webdriver', {get: () => undefined})"
})
return driver
Помощник по решению CaptchaAI
import time
import requests
API_KEY = "YOUR_API_KEY"
def solve_captcha(method, **params):
"""Generic CaptchaAI solver — works for all supported CAPTCHA types."""
submit_data = {
"key": API_KEY,
"method": method,
"json": 1,
**params,
}
submit = requests.post("https://ocr.captchaai.com/in.php", data=submit_data, timeout=30)
data = submit.json()
if data.get("status") != 1:
raise Exception(f"Submit error: {data.get('request')}")
task_id = data["request"]
for _ in range(30):
time.sleep(5)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY,
"action": "get",
"id": task_id,
"json": 1,
}, timeout=30).json()
if result.get("status") == 1:
return result["request"]
if result.get("request") == "ERROR_CAPTCHA_UNSOLVABLE":
raise Exception("CAPTCHA unsolvable")
raise TimeoutError("Solve timed out")
reCAPTCHA v2 с селеном
Полный поток: обнаружение, решение, передача токена во внутренний QA endpoint, отправка
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import re
def solve_recaptcha_v2_selenium(driver, url):
"""Complete reCAPTCHA v2 solve in Selenium."""
driver.get(url)
# Wait for page to load
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.TAG_NAME, "body"))
)
# Extract sitekey
page_source = driver.page_source
match = re.search(r'data-sitekey=["\']([A-Za-z0-9_-]{40})["\']', page_source)
if not match:
raise ValueError("reCAPTCHA sitekey not found")
sitekey = match.group(1)
print(f"Sitekey: {sitekey}")
# Solve via CaptchaAI
token = solve_captcha(
"userrecaptcha",
googlekey=sitekey,
pageurl=url,
)
print(f"Token received: {token[:50]}...")
# Inject token into the page
driver.execute_script(f"""
document.getElementById('g-recaptcha-response').value = '{token}';
document.getElementById('g-recaptcha-response').style.display = 'block';
""")
# If there's a callback function, call it
driver.execute_script(f"""
if (typeof ___grecaptcha_cfg !== 'undefined') {{
var clients = ___grecaptcha_cfg.clients;
for (var key in clients) {{
var client = clients[key];
if (client.rr && client.rr.l) {{
client.rr.l.callback('{token}');
}}
}}
}}
""")
# Submit the form
submit_button = driver.find_element(By.CSS_SELECTOR, "button[type='submit'], input[type='submit']")
submit_button.click()
return token
# Usage
driver = create_driver()
try:
solve_recaptcha_v2_selenium(driver, "https://https://staging.example.com/qa-login")
print(f"Current URL: {driver.current_url}")
finally:
driver.quit()
Cloudflare Turnstile с селеном
def solve_turnstile_selenium(driver, url):
"""Complete Turnstile solve in Selenium."""
driver.get(url)
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.TAG_NAME, "body"))
)
# Extract sitekey
page_source = driver.page_source
match = re.search(r'data-sitekey=["\']([0-9x][A-Za-z0-9_-]+)["\']', page_source)
if not match:
# Try JavaScript API pattern
match = re.search(r"sitekey\s*:\s*['\"]([0-9x][A-Za-z0-9_-]+)['\"]", page_source)
if not match:
raise ValueError("Turnstile sitekey not found")
sitekey = match.group(1)
print(f"Turnstile sitekey: {sitekey}")
# Solve via CaptchaAI
token = solve_captcha(
"turnstile",
sitekey=sitekey,
pageurl=url,
)
print(f"Turnstile token: {token[:50]}...")
# Inject token
driver.execute_script(f"""
// Set the hidden input value
var inputs = document.querySelectorAll('[name="cf-turnstile-response"]');
inputs.forEach(function(input) {{ input.value = '{token}'; }});
// Also try the callback approach
if (typeof turnstile !== 'undefined' && turnstile.getResponse) {{
// Widget already rendered
}}
""")
# Submit form
submit_button = driver.find_element(By.CSS_SELECTOR, "button[type='submit'], input[type='submit']")
submit_button.click()
return token
Изображение CAPTCHA с Selenium
Для традиционных CAPTCHA image/text (введите буквы, которые видите):
import base64
def solve_image_captcha_selenium(driver, captcha_selector):
"""Solve image CAPTCHA visible in the browser."""
# Find the CAPTCHA image element
captcha_img = driver.find_element(By.CSS_SELECTOR, captcha_selector)
# Get image as base64
img_base64 = captcha_img.screenshot_as_base64
# Solve via CaptchaAI
answer = solve_captcha("base64", body=img_base64)
print(f"CAPTCHA answer: {answer}")
# Type the answer into the input field
captcha_input = driver.find_element(
By.CSS_SELECTOR, "input[name='captcha'], input[name='code'], input.captcha-input"
)
captcha_input.clear()
captcha_input.send_keys(answer)
return answer
reCAPTCHA v3 с селеном
def solve_recaptcha_v3_selenium(driver, url, sitekey, action="verify"):
"""Solve reCAPTCHA v3 in Selenium."""
driver.get(url)
# Solve via CaptchaAI
token = solve_captcha(
"userrecaptcha",
googlekey=sitekey,
pageurl=url,
version="v3",
action=action,
)
# Inject token
driver.execute_script(f"""
// Set reCAPTCHA response
var textarea = document.getElementById('g-recaptcha-response');
if (textarea) {{
textarea.value = '{token}';
textarea.style.display = 'block';
}}
// Set any hidden input fields
var inputs = document.querySelectorAll('input[name="g-recaptcha-response"]');
inputs.forEach(function(input) {{ input.value = '{token}'; }});
""")
return token
Полный пример автоматизации
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import re
import time
import requests
API_KEY = "YOUR_API_KEY"
class SeleniumCaptchaSolver:
"""Complete Selenium + CaptchaAI automation class."""
def __init__(self, api_key):
self.api_key = api_key
self.driver = None
def start(self):
"""Initialize the browser."""
options = webdriver.ChromeOptions()
options.add_argument("--disable-blink-features=AutomationControlled")
options.add_experimental_option("excludeSwitches", ["enable-automation"])
self.driver = webdriver.Chrome(options=options)
self.driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
"source": "Object.defineProperty(navigator, 'webdriver', {get: () => undefined})"
})
def stop(self):
"""Close the browser."""
if self.driver:
self.driver.quit()
def navigate(self, url):
"""Navigate to URL and wait for load."""
self.driver.get(url)
WebDriverWait(self.driver, 15).until(
lambda d: d.execute_script("return document.readyState") == "complete"
)
def detect_captcha(self):
"""Detect which CAPTCHA type is on the page."""
source = self.driver.page_source
if re.search(r'data-sitekey=["\'][A-Za-z0-9_-]{40}["\']', source):
if "recaptcha/api.js" in source or "grecaptcha" in source:
return "recaptcha_v2"
if "cf-turnstile" in source or "challenges.cloudflare.com/turnstile" in source:
return "turnstile"
if re.search(r'recaptcha.*v3|render=[A-Za-z0-9_-]{40}', source):
return "recaptcha_v3"
captcha_imgs = self.driver.find_elements(
By.CSS_SELECTOR, "img.captcha, img[alt*='captcha'], img[src*='captcha']"
)
if captcha_imgs:
return "image"
return None
def solve_and_submit(self, url, form_data=None):
"""Navigate, solve CAPTCHA, fill form, and submit."""
self.navigate(url)
captcha_type = self.detect_captcha()
if not captcha_type:
print("No CAPTCHA detected")
return self._fill_and_submit(form_data)
print(f"Detected: {captcha_type}")
if captcha_type == "recaptcha_v2":
self._solve_recaptcha_v2()
elif captcha_type == "turnstile":
self._solve_turnstile()
elif captcha_type == "image":
self._solve_image()
return self._fill_and_submit(form_data)
def _solve_recaptcha_v2(self):
source = self.driver.page_source
match = re.search(r'data-sitekey=["\']([A-Za-z0-9_-]{40})["\']', source)
sitekey = match.group(1)
token = self._api_solve("userrecaptcha", googlekey=sitekey, pageurl=self.driver.current_url)
self.driver.execute_script(f"""
document.getElementById('g-recaptcha-response').value = '{token}';
""")
def _solve_turnstile(self):
source = self.driver.page_source
match = re.search(r'data-sitekey=["\']([0-9x][A-Za-z0-9_-]+)["\']', source)
sitekey = match.group(1)
token = self._api_solve("turnstile", sitekey=sitekey, pageurl=self.driver.current_url)
self.driver.execute_script(f"""
document.querySelectorAll('[name="cf-turnstile-response"]')
.forEach(function(el) {{ el.value = '{token}'; }});
""")
def _solve_image(self):
img = self.driver.find_element(
By.CSS_SELECTOR, "img.captcha, img[alt*='captcha'], img[src*='captcha']"
)
answer = self._api_solve("base64", body=img.screenshot_as_base64)
captcha_input = self.driver.find_element(
By.CSS_SELECTOR, "input[name='captcha'], input[name='code']"
)
captcha_input.clear()
captcha_input.send_keys(answer)
def _fill_and_submit(self, form_data):
if form_data:
for name, value in form_data.items():
try:
field = self.driver.find_element(By.NAME, name)
field.clear()
field.send_keys(value)
except Exception:
pass
submit = self.driver.find_element(
By.CSS_SELECTOR, "button[type='submit'], input[type='submit']"
)
submit.click()
time.sleep(3)
return self.driver.current_url
def _api_solve(self, method, **params):
submit = requests.post("https://ocr.captchaai.com/in.php", data={
"key": self.api_key, "method": method, "json": 1, **params,
}, timeout=30)
data = submit.json()
if data.get("status") != 1:
raise Exception(f"Submit error: {data.get('request')}")
task_id = data["request"]
for _ in range(30):
time.sleep(5)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": self.api_key, "action": "get", "id": task_id, "json": 1,
}, timeout=30).json()
if result.get("status") == 1:
return result["request"]
raise TimeoutError("Solve timed out")
# Usage
solver = SeleniumCaptchaSolver(API_KEY)
solver.start()
try:
result_url = solver.solve_and_submit(
"https://https://staging.example.com/qa-login",
form_data={"username": "user@example.com", "password": "pass123"},
)
print(f"Result: {result_url}")
finally:
solver.stop()
Поиск неисправностей
| Симптом | Причина | Исправить |
|---|---|---|
| CAPTCHA обнаружена, но передача токена во внутренний QA endpoint не выполнено | g-recaptcha-response не найден |
Проверьте наличие iframe — reCAPTCHA может находиться в iframe. |
| Токен введен, но форма не отправляется | Обратный звонок не запущен | Явно вызовите функцию обратного вызова reCAPTCHA. |
| «Веб-драйвер обнаружен» сайтом | стандартная конфигурация браузера-конфигурация не применена | Добавьте команду CDP для удаления флага веб-драйвера |
| Скриншот изображения CAPTCHA пустой | Элемент не виден | Сначала прокрутите элемент в поле зрения |
| токен Cloudflare Turnstile отклонен | Неправильный ключ сайта | Повторное извлечение из источника активной страницы |
Часто задаваемые вопросы
Должен ли я использовать Selenium или чистые запросы?
Используйте Selenium, когда сайт требует выполнения JavaScript, динамической загрузки контента или сложных многостраничных потоков. Используйте requests для простой отправки форм на основе API, где вам просто нужен токен.
Как обрабатывать reCAPTCHA в iframe?
Сначала переключитесь на iframe reCAPTCHA: driver.switch_to.frame(driver.find_element(By.CSS_SELECTOR, "iframe[src*='recaptcha']")). Извлеките ключ сайта, затем переключитесь обратно: driver.switch_to.default_content().
Могу ли я запустить Selenium без головы?
Да, но некоторые CAPTCHA обнаруживают безгласный режим. Используйте --headless=new и убедитесь, что сигналы браузера WebGL/Canvas действительны. CaptchaAI решает самостоятельно, поэтому обезглавленное обнаружение не влияет на решение.
Насколько медленнее Selenium по сравнению с запросами?
Selenium добавляет 3-5 секунд на запуск браузера и рендеринг страницы. Время решения CAPTCHA такое же. По возможности используйте requests, а при необходимости — Selenium.
Краткое содержание
Питон Селен +CaptchaAIобрабатывает любую CAPTCHA в автоматизации браузера: определяет тип CAPTCHA из источника страницы, решает с помощью API CaptchaAI, внедряет токен с помощью JavaScript и отправляет форму. Класс SeleniumCaptchaSolver автоматизирует полный рабочий процесс обнаружения-решения-отправки.