
Lucas Mitchell
Automation Engineer

Web automation has become essential for data collection, testing, and various business operations. However, modern websites deploy sophisticated anti-bot measures and CAPTCHAs that can halt even the most carefully crafted automation scripts.
The combination of DrissionPage and CapSolver provides a powerful solution to this challenge:
Together, these tools enable seamless web automation that bypasses both WebDriver detection and CAPTCHA challenges.
This guide will help you achieve three core goals:
DrissionPage is a Python-based web automation tool that combines browser control with HTTP request capabilities. Unlike Selenium, it uses a self-developed kernel that doesn't rely on WebDriver, making it harder to detect.
# Install DrissionPage
pip install DrissionPage
# Install requests library for CapSolver API
pip install requests
from DrissionPage import ChromiumPage
# Create browser instance
page = ChromiumPage()
# Navigate to URL
page.get('https://wikipedia.org')
# Find and interact with elements
page('#search-input').input('Hello World')
page('#submit-btn').click()
CapSolver is an AI-powered automatic CAPTCHA solving service that supports a wide range of CAPTCHA types. It provides a simple API that allows you to submit CAPTCHA challenges and receive solutions within seconds.
https://api.capsolver.comhttps://api-stable.capsolver.comBefore combining DrissionPage with CapSolver, web automation faced several pain points:
| Challenge | Impact |
|---|---|
| WebDriver detection | Selenium scripts blocked immediately |
| CAPTCHA challenges | Manual solving required, breaking automation |
| iframe complexity | Difficult to interact with nested content |
| Multi-tab operations | Required complex tab switching logic |
The DrissionPage + CapSolver integration solves all these challenges in one workflow.
The API integration approach gives you full control over the CAPTCHA solving process and works with any CAPTCHA type.
pip install DrissionPage requests
import time
import requests
from DrissionPage import ChromiumPage
CAPSOLVER_API_KEY = "YOUR_API_KEY"
CAPSOLVER_API = "https://api.capsolver.com"
def create_task(task_payload: dict) -> str:
"""Create a CAPTCHA solving task and return the task ID."""
response = requests.post(
f"{CAPSOLVER_API}/createTask",
json={
"clientKey": CAPSOLVER_API_KEY,
"task": task_payload
}
)
result = response.json()
if result.get("errorId") != 0:
raise Exception(f"CapSolver error: {result.get('errorDescription')}")
return result["taskId"]
def get_task_result(task_id: str, max_attempts: int = 120) -> dict:
"""Poll for task result until solved or timeout."""
for _ in range(max_attempts):
response = requests.post(
f"{CAPSOLVER_API}/getTaskResult",
json={
"clientKey": CAPSOLVER_API_KEY,
"taskId": task_id
}
)
result = response.json()
if result.get("status") == "ready":
return result["solution"]
elif result.get("status") == "failed":
raise Exception(f"Task failed: {result.get('errorDescription')}")
time.sleep(1)
raise TimeoutError("CAPTCHA solving timed out")
def solve_captcha(task_payload: dict) -> dict:
"""Complete CAPTCHA solving workflow."""
task_id = create_task(task_payload)
return get_task_result(task_id)
You can also use the CapSolver browser extension with DrissionPage for a more hands-off approach.
config.js file:// In the extension folder, edit: assets/config.js
var defined = {
apiKey: "YOUR_CAPSOLVER_API_KEY", // Replace with your actual API key
enabledForBlacklistControl: false,
blackUrlList: [],
enabledForRecaptcha: true,
enabledForRecaptchaV3: true,
enabledForTurnstile: true,
// ... other settings
}
from DrissionPage import ChromiumPage, ChromiumOptions
co = ChromiumOptions()
co.add_extension('/path/to/capsolver-extension')
page = ChromiumPage(co)
# The extension will automatically detect and solve CAPTCHAs
Note: The extension must have a valid API key configured before it can solve CAPTCHAs automatically.
Cloudflare Turnstile is one of the most common CAPTCHA challenges. Here's how to solve it:
import time
import requests
from DrissionPage import ChromiumPage
CAPSOLVER_API_KEY = "YOUR_API_KEY"
CAPSOLVER_API = "https://api.capsolver.com"
def solve_turnstile(site_key: str, page_url: str) -> str:
"""Solve Cloudflare Turnstile and return the token."""
# Create the task
response = requests.post(
f"{CAPSOLVER_API}/createTask",
json={
"clientKey": CAPSOLVER_API_KEY,
"task": {
"type": "AntiTurnstileTaskProxyLess",
"websiteURL": page_url,
"websiteKey": site_key,
}
}
)
result = response.json()
if result.get("errorId") != 0:
raise Exception(f"Error: {result.get('errorDescription')}")
task_id = result["taskId"]
# Poll for result
while True:
result = requests.post(
f"{CAPSOLVER_API}/getTaskResult",
json={
"clientKey": CAPSOLVER_API_KEY,
"taskId": task_id
}
).json()
if result.get("status") == "ready":
return result["solution"]["token"]
elif result.get("status") == "failed":
raise Exception(f"Failed: {result.get('errorDescription')}")
time.sleep(1)
def main():
target_url = "https://your-target-site.com"
turnstile_site_key = "0x4XXXXXXXXXXXXXXXXX" # Find this in page source
# Create browser instance
page = ChromiumPage()
page.get(target_url)
# Wait for Turnstile to load
page.wait.ele_displayed('input[name="cf-turnstile-response"]', timeout=10)
# Solve the CAPTCHA
token = solve_turnstile(turnstile_site_key, target_url)
print(f"Got Turnstile token: {token[:50]}...")
# Inject the token using JavaScript
page.run_js(f'''
document.querySelector('input[name="cf-turnstile-response"]').value = "{token}";
// Also trigger the callback if present
const callback = document.querySelector('[data-callback]');
if (callback) {{
const callbackName = callback.getAttribute('data-callback');
if (window[callbackName]) {{
window[callbackName]('{token}');
}}
}}
''')
# Submit the form
page('button[type="submit"]').click()
page.wait.load_start()
print("Successfully bypassed Turnstile!")
if __name__ == "__main__":
main()
This example automatically detects the site key from the page - no manual configuration needed:
import time
import requests
from DrissionPage import ChromiumPage, ChromiumOptions
CAPSOLVER_API_KEY = "YOUR_API_KEY"
CAPSOLVER_API = "https://api.capsolver.com"
def solve_recaptcha_v2(site_key: str, page_url: str) -> str:
"""Solve reCAPTCHA v2 and return the token."""
# Create the task
response = requests.post(
f"{CAPSOLVER_API}/createTask",
json={
"clientKey": CAPSOLVER_API_KEY,
"task": {
"type": "ReCaptchaV2TaskProxyLess",
"websiteURL": page_url,
"websiteKey": site_key,
}
}
)
result = response.json()
if result.get("errorId") != 0:
raise Exception(f"Error: {result.get('errorDescription')}")
task_id = result["taskId"]
print(f"Task created: {task_id}")
# Poll for result
while True:
result = requests.post(
f"{CAPSOLVER_API}/getTaskResult",
json={
"clientKey": CAPSOLVER_API_KEY,
"taskId": task_id
}
).json()
if result.get("status") == "ready":
return result["solution"]["gRecaptchaResponse"]
elif result.get("status") == "failed":
raise Exception(f"Failed: {result.get('errorDescription')}")
time.sleep(1)
def main():
# Just provide the URL - site key will be auto-detected
target_url = "https://www.google.com/recaptcha/api2/demo"
# Configure browser
co = ChromiumOptions()
co.set_argument('--disable-blink-features=AutomationControlled')
print("Starting browser...")
page = ChromiumPage(co)
try:
page.get(target_url)
time.sleep(2)
# Auto-detect site key from page
recaptcha_div = page('.g-recaptcha')
if not recaptcha_div:
print("No reCAPTCHA found on page!")
return
site_key = recaptcha_div.attr('data-sitekey')
print(f"Auto-detected site key: {site_key}")
# Solve the CAPTCHA
print("Solving reCAPTCHA v2...")
token = solve_recaptcha_v2(site_key, target_url)
print(f"Got token: {token[:50]}...")
# Inject the token
page.run_js(f'''
var responseField = document.getElementById('g-recaptcha-response');
responseField.style.display = 'block';
responseField.value = '{token}';
''')
print("Token injected!")
# Submit the form
submit_btn = page('#recaptcha-demo-submit') or page('input[type="submit"]') or page('button[type="submit"]')
if submit_btn:
submit_btn.click()
time.sleep(3)
print("Form submitted!")
print(f"Current URL: {page.url}")
print("SUCCESS!")
finally:
page.quit()
if __name__ == "__main__":
main()
Test it yourself:
python recaptcha_demo.py
This will open Google's reCAPTCHA demo page, automatically detect the site key, solve the CAPTCHA, and submit the form.
reCAPTCHA v3 is score-based and doesn't require user interaction. You need to specify the action parameter.
import time
import requests
from DrissionPage import ChromiumPage, ChromiumOptions
CAPSOLVER_API_KEY = "YOUR_API_KEY"
CAPSOLVER_API = "https://api.capsolver.com"
def solve_recaptcha_v3(
site_key: str,
page_url: str,
action: str = "verify",
min_score: float = 0.7
) -> str:
"""Solve reCAPTCHA v3 with specified action and minimum score."""
response = requests.post(
f"{CAPSOLVER_API}/createTask",
json={
"clientKey": CAPSOLVER_API_KEY,
"task": {
"type": "ReCaptchaV3TaskProxyLess",
"websiteURL": page_url,
"websiteKey": site_key,
"pageAction": action,
"minScore": min_score
}
}
)
result = response.json()
if result.get("errorId") != 0:
raise Exception(f"Error: {result.get('errorDescription')}")
task_id = result["taskId"]
while True:
result = requests.post(
f"{CAPSOLVER_API}/getTaskResult",
json={
"clientKey": CAPSOLVER_API_KEY,
"taskId": task_id
}
).json()
if result.get("status") == "ready":
return result["solution"]["gRecaptchaResponse"]
elif result.get("status") == "failed":
raise Exception(f"Failed: {result.get('errorDescription')}")
time.sleep(1)
def main():
target_url = "https://your-target-site.com"
recaptcha_v3_key = "6LcXXXXXXXXXXXXXXXXXXXXXXXXX"
# Setup headless browser for v3
co = ChromiumOptions()
co.headless()
page = ChromiumPage(co)
page.get(target_url)
# Solve reCAPTCHA v3 with "search" action
print("Solving reCAPTCHA v3...")
token = solve_recaptcha_v3(
recaptcha_v3_key,
target_url,
action="search",
min_score=0.9 # Request high score
)
# Execute the callback with the token
page.run_js(f'''
// If there's a callback function, call it with the token
if (typeof onRecaptchaSuccess === 'function') {{
onRecaptchaSuccess('{token}');
}}
// Or set the hidden field value
var responseField = document.querySelector('[name="g-recaptcha-response"]');
if (responseField) {{
responseField.value = '{token}';
}}
''')
print("reCAPTCHA v3 bypassed!")
if __name__ == "__main__":
main()
DrissionPage's action chains provide natural mouse movements and keyboard interactions:
import time
import random
from DrissionPage import ChromiumPage
from DrissionPage.common import Keys, Actions
def human_delay():
"""Random delay to mimic human behavior."""
time.sleep(random.uniform(0.5, 1.5))
def main():
page = ChromiumPage()
page.get('https://your-target-site.com/form')
# Use action chains for human-like interactions
ac = Actions(page)
# Move to input field naturally, then click and type
ac.move_to('input[name="email"]').click()
human_delay()
# Type slowly like a human
for char in "user@email.com":
ac.type(char)
time.sleep(random.uniform(0.05, 0.15))
human_delay()
# Move to password field
ac.move_to('input[name="password"]').click()
human_delay()
# Type password
page('input[name="password"]').input("mypassword123")
# After solving CAPTCHA, click submit with natural movement
ac.move_to('button[type="submit"]')
human_delay()
ac.click()
if __name__ == "__main__":
main()
Configure DrissionPage to appear more like a regular browser:
from DrissionPage import ChromiumPage, ChromiumOptions
co = ChromiumOptions()
co.set_argument('--disable-blink-features=AutomationControlled')
co.set_argument('--no-sandbox')
co.set_user_agent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36')
# Set window size to common resolution
co.set_argument('--window-size=1920,1080')
page = ChromiumPage(co)
from DrissionPage import ChromiumPage, ChromiumOptions
co = ChromiumOptions()
co.incognito() # Use incognito mode
co.headless() # Run headless (for v3 CAPTCHAs)
page = ChromiumPage(co)
Avoid triggering rate limits by adding random delays:
import random
import time
def human_delay(min_sec=1.0, max_sec=3.0):
"""Random delay to mimic human behavior."""
time.sleep(random.uniform(min_sec, max_sec))
# Use between actions
page('#button1').click()
human_delay()
page('#input1').input('text')
Always implement proper error handling for CAPTCHA solving:
def solve_with_retry(task_payload: dict, max_retries: int = 3) -> dict:
"""Solve CAPTCHA with retry logic."""
for attempt in range(max_retries):
try:
return solve_captcha(task_payload)
except TimeoutError:
if attempt < max_retries - 1:
print(f"Timeout, retrying... ({attempt + 1}/{max_retries})")
time.sleep(5)
else:
raise
except Exception as e:
if "balance" in str(e).lower():
raise # Don't retry balance errors
if attempt < max_retries - 1:
time.sleep(2)
else:
raise
Use proxies with DrissionPage for IP rotation:
from DrissionPage import ChromiumPage, ChromiumOptions
co = ChromiumOptions()
co.set_proxy('http://username:password@proxy.example.com:8080')
page = ChromiumPage(co)
The integration of DrissionPage and CapSolver creates a powerful toolkit for web automation:
Whether you're building web scrapers, automated testing systems, or data collection pipelines, this combination provides the reliability and stealth you need.
Bonus: Use code
DRISSIONwhen signing up at CapSolver to receive bonus credits!
DrissionPage doesn't use WebDriver, which means:
CapSolver supports all major CAPTCHA types. Cloudflare Turnstile and reCAPTCHA v2/v3 have the highest success rates. The integration works seamlessly with any CAPTCHA that CapSolver supports.
Yes! DrissionPage supports headless mode. For reCAPTCHA v3 and token-based CAPTCHAs, headless mode works perfectly. For v2 visible CAPTCHAs, headed mode may provide better results.
Look in the page source for:
data-sitekey attribute or cf-turnstile elementsdata-sitekey attribute on g-recaptcha divCommon solutions:
Yes! DrissionPage has built-in support for shadow DOM elements through the ChromiumShadowElement class.
Learn scalable Rust web scraping architecture with reqwest, scraper, async scraping, headless browser scraping, proxy rotation, and compliant CAPTCHA handling.

Learn the best techniques to scrape job listings without getting blocked. Master Indeed scraping, Google Jobs API, and web scraping API with CapSolver.
