| name | pydoll-antibot-bypasser |
| description | Stealth browser automation using pydoll library, specialized in bypassing Cloudflare WAF, Turnstile CAPTCHA, and other bot detection systems. **Must invoke this skill when users need to bypass WAF (Cloudflare, DataDome, PerimeterX, etc.) or human verification.** Also suitable for: anti-scraping bypass, stealth browser operations, crawling protected websites, handling Shadow DOM, simulating human behavior, and web automation testing. |
Pydoll Antibot Bypasser Skill
Pydoll is an async-native, zero WebDriver dependency Chromium browser automation library designed for stealth and human-like interaction.
Quick Reference
Core Features
| Feature | Description |
|---|
| Zero WebDriver | Direct WebSocket connection to CDP, no navigator.webdriver flag |
| Human-like Interaction | Bezier curve mouse + typing error simulation |
| Shadow DOM | Can access closed shadow roots |
| Cloudflare | Built-in Turnstile auto-handling |
| Async Performance | 100% async, supports concurrency |
WAF Bypass Support
| WAF | Status | Notes |
|---|
| Cloudflare Turnstile | ✅ Fully Supported | Works in headless mode |
| Cloudflare JS Challenge | ✅ Supported | Auto-executes JS |
| Cloudflare Managed Challenge | ✅ Verified | Requires headless=False + xvfb |
| DataDome | ⚠️ Partial Support | Needs high-quality proxy |
| PerimeterX | ⚠️ Partial Support | Needs randomized behavior |
| reCAPTCHA | ⚠️ Manual Handling | Via Shadow DOM |
Running Methods
uv run script.py
pip install pydoll-python
Core Code Template
import asyncio
import time
from pydoll.browser import Chrome
from pydoll.browser.options import ChromiumOptions
async def main():
options = ChromiumOptions()
options.headless = True
fake_engagement_time = int(time.time()) - (7 * 24 * 60 * 60)
options.browser_preferences = {
'profile': {
'last_engagement_time': fake_engagement_time,
'exit_type': 'Normal',
'exited_cleanly': True,
},
}
options.webrtc_leak_protection = True
options.add_argument('--no-sandbox')
options.add_argument('--disable-dev-shm-usage')
async with Chrome(options=options) as browser:
tab = await browser.start()
async with tab.expect_and_bypass_cloudflare_captcha():
await tab.go_to('https://protected-site.com')
print(await tab.title)
if __name__ == '__main__':
asyncio.run(main())
Browser Configuration
Basic Configuration
from pydoll.browser import Chrome
from pydoll.browser.options import ChromiumOptions
options = ChromiumOptions()
options.headless = True
options.add_argument('--window-size=1920,1080')
options.start_timeout = 20
options.binary_location = '/usr/bin/google-chrome-stable'
Anti-Detection Configuration (Required)
import time
fake_engagement_time = int(time.time()) - (7 * 24 * 60 * 60)
options.browser_preferences = {
'profile': {
'last_engagement_time': fake_engagement_time,
'exit_type': 'Normal',
'exited_cleanly': True,
'default_content_setting_values': {
'notifications': 2,
'geolocation': 2,
},
'password_manager_enabled': False,
},
'intl': {
'accept_languages': 'en-US,en',
},
}
options.webrtc_leak_protection = True
Proxy Configuration
options.add_argument('--proxy-server=http://user:pass@proxy:8080')
context_id = await browser.create_browser_context(
proxy_server='http://proxy:8080'
)
Cloudflare Bypass
Method 1: Context Manager (Recommended)
async with Chrome() as browser:
tab = await browser.start()
async with tab.expect_and_bypass_cloudflare_captcha():
await tab.go_to('https://protected-site.com')
Method 2: Enable/Disable
await tab.enable_auto_solve_cloudflare_captcha()
await tab.go_to('https://protected-site.com')
await asyncio.sleep(5)
await tab.disable_auto_solve_cloudflare_captcha()
Managed Challenge Bypass (Important)
Key Finding: Managed Challenge detects headless mode, must use headless=False
| Mode | Result |
|---|
headless=True | ❌ Infinite wait |
headless=False | ✅ Successful bypass |
Server Environment:
apt-get install -y xvfb
xvfb-run -a --server-args="-screen 0 1920x1080x24" uv run script.py
Element Operations
Finding Elements
button = await tab.find(tag_name='button', class_name='btn-primary')
username = await tab.find(id='username')
nav = await tab.query('nav.main-menu')
links = await tab.find(tag_name='a', find_all=True)
element = await tab.find(class_name='dynamic', timeout=10, raise_exc=False)
Interaction Operations
await button.click()
await input_element.type_text('Hello World', humanize=True)
await input_element.insert_text('value')
await input_element.clear()
async with tab.expect_file_chooser() as fc:
await upload_btn.click()
await fc.upload_file('/path/to/file')
Keyboard/Mouse Operations
from pydoll.constants import Key
await tab.keyboard.press(Key.ENTER)
await tab.keyboard.hotkey(Key.CONTROL, Key.A)
await tab.mouse.move(500, 300, humanize=True)
await tab.mouse.click(500, 300, humanize=True)
from pydoll.constants import ScrollPosition
await tab.scroll.by(ScrollPosition.DOWN, 500, smooth=True)
Shadow DOM
shadow = await element.get_shadow_root()
button = await shadow.query('.internal-btn')
shadow_roots = await tab.find_shadow_roots()
for sr in shadow_roots:
checkbox = await sr.query('input[type="checkbox"]', raise_exc=False)
if checkbox:
await checkbox.click()
shadow_roots = await tab.find_shadow_roots(deep=True, timeout=10)
Network Control
Hybrid Automation (UI + API)
response = await tab.request.get('https://example.com/api/profile')
user_data = response.json()
Request Interception
from pydoll.protocol.fetch.events import FetchEvent, RequestPausedEvent
from pydoll.protocol.network.types import ErrorReason
async def block_resources(event: RequestPausedEvent):
rid = event['params']['requestId']
rtype = event['params']['resourceType']
if rtype in ['Image', 'Stylesheet', 'Font', 'Media']:
await tab.fail_request(rid, ErrorReason.BLOCKED_BY_CLIENT)
else:
await tab.continue_request(rid)
await tab.enable_fetch_events()
await tab.on(FetchEvent.REQUEST_PAUSED, block_resources)
await tab.go_to('https://example.com')
await tab.disable_fetch_events()
Tab Management
tab2 = await browser.new_tab(url='https://example.com')
context_id = await browser.create_browser_context()
tab3 = await browser.new_tab(browser_context_id=context_id)
tabs = await browser.get_opened_tabs()
await tab.close()
Screenshot & Download
await tab.take_screenshot(path='screenshot.png')
await tab.take_screenshot(path='full.png', full_page=True)
await tab.print_to_pdf(path='page.pdf')
from pathlib import Path
async with tab.expect_download(keep_file_at=Path('/tmp')) as dl:
await (await tab.find(text='Download')).click()
print(f"Downloaded to: {dl.file_path}")
Exception Handling
from pydoll.exceptions import ElementNotFound, PageLoadTimeout, NetworkError
try:
element = await tab.find(id='button', timeout=5)
except ElementNotFound:
print("Element not found")
except PageLoadTimeout:
print("Page load timeout")
from pydoll.decorators import retry
@retry(max_retries=3, exceptions=[ElementNotFound, NetworkError])
async def scrape_page(tab, url):
await tab.go_to(url)
return await tab.title
Complete Examples
See examples/ directory for detailed code examples:
| File | Description |
|---|
bypass_cloudflare.py | Cloudflare WAF bypass |
bypass_managed_challenge.py | Managed Challenge bypass |
stealth_scraper.py | Full anti-detection scraper |
concurrent_scraper.py | Concurrent scraping |
screenshot.py | Batch screenshots |
Common templates in scripts/templates.py, includes 8 ready-to-use templates.
Troubleshooting
| Problem | Solution |
|---|
| Browser not found | options.binary_location = '/path/to/chrome' |
| Startup timeout | options.start_timeout = 20 |
| Docker crash | Add --no-sandbox and --disable-dev-shm-usage |
| Element not found | Increase timeout or use raise_exc=False |
| Detected as bot | Enable humanize=True, configure browser fingerprint |
| Cloudflare failed | Use expect_and_bypass_cloudflare_captcha() |
| Managed Challenge failed | Use headless=False + xvfb |
References
Important: When using this library for scraping, please comply with target website's robots.txt and terms of service.