Enhanced Python module to bypass Cloudflare's anti-bot page with support for v1, v2, v3 challenges, Turnstile, proxy rotation, and stealth mode.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Comprehensive support for all Cloudflare challenge types including legacy v1, modern v2, advanced v3 JavaScript VM challenges, and Turnstile CAPTCHA alternatives. CloudScraper automatically detects and solves these challenges transparently.
Handler for legacy Cloudflare v1 challenges that use simple JavaScript validation and timing delays.
class Cloudflare:
def __init__(self, cloudscraper):
"""Initialize v1 challenge handler."""
@staticmethod
def is_Challenge_Request(resp) -> bool:
"""
Detect if response contains a v1 challenge.
Parameters:
- resp: requests.Response object
Returns:
bool: True if v1 challenge detected
"""
@staticmethod
def is_IUAM_Challenge(resp) -> bool:
"""
Detect IUAM (I'm Under Attack Mode) challenge.
Parameters:
- resp: requests.Response object
Returns:
bool: True if IUAM challenge detected
"""
def Challenge_Response(self, resp, **kwargs):
"""
Handle v1 challenge solving.
Parameters:
- resp: requests.Response containing challenge
- **kwargs: request parameters
Returns:
requests.Response with solved challenge
Raises:
- CloudflareIUAMError: If challenge parameters cannot be extracted
- CloudflareSolveError: If challenge solving fails
"""# v1 challenges are handled automatically
scraper = cloudscraper.create_scraper()
response = scraper.get('https://legacy-protected-site.com')
# Disable v1 handling if needed
scraper = cloudscraper.create_scraper(disableCloudflareV1=True)
# Manual v1 detection (normally not needed)
if cloudscraper.Cloudflare.is_Challenge_Request(response):
print("v1 challenge detected")Handler for modern Cloudflare v2 challenges that include JavaScript execution and CAPTCHA verification.
class CloudflareV2:
def __init__(self, cloudscraper):
"""Initialize v2 challenge handler."""
@staticmethod
def is_V2_Challenge(resp) -> bool:
"""
Detect v2 JavaScript challenge.
Parameters:
- resp: requests.Response object
Returns:
bool: True if v2 JS challenge detected
"""
@staticmethod
def is_V2_Captcha_Challenge(resp) -> bool:
"""
Detect v2 CAPTCHA challenge.
Parameters:
- resp: requests.Response object
Returns:
bool: True if v2 CAPTCHA challenge detected
"""
def handle_V2_Challenge(self, resp, **kwargs):
"""
Handle v2 JavaScript challenge.
Parameters:
- resp: requests.Response containing challenge
- **kwargs: request parameters
Returns:
requests.Response with solved challenge
Raises:
- CloudflareChallengeError: If challenge cannot be solved
"""
def handle_V2_Captcha_Challenge(self, resp, **kwargs):
"""
Handle v2 CAPTCHA challenge.
Parameters:
- resp: requests.Response containing challenge
- **kwargs: request parameters
Returns:
requests.Response with solved challenge
Raises:
- CloudflareCaptchaError: If CAPTCHA cannot be solved
- CloudflareCaptchaProvider: If no CAPTCHA solver configured
"""
def extract_challenge_data(self, resp) -> dict:
"""
Extract v2 challenge parameters from response.
Parameters:
- resp: requests.Response containing challenge
Returns:
dict: Challenge parameters and JavaScript code
Raises:
- CloudflareChallengeError: If challenge data cannot be extracted
"""
def generate_challenge_payload(self, challenge_data, resp) -> dict:
"""
Generate payload for v2 challenge submission.
Parameters:
- challenge_data: dict, extracted challenge parameters
- resp: requests.Response, original challenge response
Returns:
dict: Challenge solution payload
"""# v2 challenges handled automatically
scraper = cloudscraper.create_scraper()
response = scraper.get('https://v2-protected-site.com')
# With CAPTCHA solver for v2 CAPTCHA challenges
scraper = cloudscraper.create_scraper(
captcha={
'provider': '2captcha',
'api_key': 'your_api_key'
}
)
# Disable v2 handling
scraper = cloudscraper.create_scraper(disableCloudflareV2=True)Handler for advanced Cloudflare v3 challenges that execute JavaScript in a virtual machine environment for enhanced security.
class CloudflareV3:
def __init__(self, cloudscraper):
"""Initialize v3 challenge handler."""
@staticmethod
def is_V3_Challenge(resp) -> bool:
"""
Detect v3 JavaScript VM challenge.
Parameters:
- resp: requests.Response object
Returns:
bool: True if v3 challenge detected
"""
def extract_v3_challenge_data(self, resp) -> dict:
"""
Extract v3 challenge parameters from response.
Parameters:
- resp: requests.Response containing challenge
Returns:
dict: Challenge parameters and data
Raises:
- CloudflareV3Error: If challenge data cannot be extracted
"""
def handle_V3_Challenge(self, resp, **kwargs):
"""
Handle v3 JavaScript VM challenge.
Parameters:
- resp: requests.Response containing challenge
- **kwargs: request parameters
Returns:
requests.Response with solved challenge
Raises:
- CloudflareV3Error: If challenge cannot be solved
"""
def execute_vm_challenge(self, challenge_data, domain) -> str:
"""
Execute JavaScript VM challenge code.
Parameters:
- challenge_data: dict, extracted challenge parameters
- domain: str, target domain for challenge
Returns:
str: Challenge solution result
Raises:
- CloudflareV3Error: If VM execution fails
"""
def generate_fallback_response(self, challenge_data) -> str:
"""
Generate fallback response when VM execution fails.
Parameters:
- challenge_data: dict, challenge parameters
Returns:
str: Fallback challenge response
"""
def generate_v3_challenge_payload(self, challenge_data, resp, challenge_answer) -> dict:
"""
Generate payload for v3 challenge submission.
Parameters:
- challenge_data: dict, extracted challenge parameters
- resp: requests.Response, original challenge response
- challenge_answer: str, computed challenge solution
Returns:
dict: Challenge solution payload
"""# v3 challenges handled automatically
scraper = cloudscraper.create_scraper()
response = scraper.get('https://v3-protected-site.com')
# Optimized for v3 challenges
scraper = cloudscraper.create_scraper(
interpreter='js2py', # Recommended for v3
delay=5, # Allow more time for complex challenges
debug=True # See v3 detection
)
# Disable v3 handling
scraper = cloudscraper.create_scraper(disableCloudflareV3=True)Handler for Cloudflare Turnstile challenges, which are CAPTCHA alternatives that provide user-friendly verification.
class CloudflareTurnstile:
def __init__(self, cloudscraper):
"""Initialize Turnstile challenge handler."""
@staticmethod
def is_Turnstile_Challenge(resp) -> bool:
"""
Detect Turnstile challenge.
Parameters:
- resp: requests.Response object
Returns:
bool: True if Turnstile challenge detected
"""
def extract_turnstile_data(self, resp) -> dict:
"""
Extract Turnstile challenge parameters.
Parameters:
- resp: requests.Response containing challenge
Returns:
dict: Turnstile site key and parameters
Raises:
- CloudflareTurnstileError: If Turnstile data cannot be extracted
"""
def handle_Turnstile_Challenge(self, resp, **kwargs):
"""
Handle Turnstile challenge solving.
Parameters:
- resp: requests.Response containing challenge
- **kwargs: request parameters
Returns:
requests.Response with solved challenge
Raises:
- CloudflareTurnstileError: If Turnstile cannot be solved
- CloudflareCaptchaProvider: If no CAPTCHA solver configured
"""# Turnstile challenges handled automatically with CAPTCHA solver
scraper = cloudscraper.create_scraper(
captcha={
'provider': '2captcha',
'api_key': 'your_api_key'
}
)
response = scraper.get('https://turnstile-protected-site.com')
# Different CAPTCHA providers work with Turnstile
providers = ['2captcha', 'anticaptcha', 'capsolver', 'capmonster']
for provider in providers:
scraper = cloudscraper.create_scraper(
captcha={'provider': provider, 'api_key': 'key'}
)
# Disable Turnstile handling
scraper = cloudscraper.create_scraper(disableTurnstile=True)CloudScraper automatically detects and handles challenges in priority order:
# All challenge types enabled by default
scraper = cloudscraper.create_scraper()
# Selective challenge handling
scraper = cloudscraper.create_scraper(
disableCloudflareV1=True, # Skip legacy challenges
disableCloudflareV2=False, # Handle v2 challenges
disableCloudflareV3=False, # Handle v3 challenges
disableTurnstile=False # Handle Turnstile
)Different interpreters work better with different challenge types:
# Recommended interpreters by challenge type
interpreters = {
'v1': ['js2py', 'nodejs', 'native'],
'v2': ['js2py', 'nodejs', 'v8'],
'v3': ['js2py', 'nodejs'], # js2py recommended for v3
'turnstile': ['any'] # Uses CAPTCHA solver, not interpreter
}
# Configure interpreter
scraper = cloudscraper.create_scraper(interpreter='js2py')Configure delays and timeouts for challenge solving:
# Custom challenge timing
scraper = cloudscraper.create_scraper(
delay=5, # Wait 5 seconds before submitting solution
solveDepth=3 # Maximum challenge solving attempts
)Enable debug output to see challenge detection and solving:
scraper = cloudscraper.create_scraper(debug=True)
response = scraper.get('https://protected-site.com')
# Debug output shows:
# "Detected a Cloudflare v3 JavaScript VM challenge."
# "Solving challenge with js2py interpreter..."
# "Challenge solved successfully"Challenge handling can raise specific exceptions:
try:
scraper = cloudscraper.create_scraper()
response = scraper.get('https://protected-site.com')
except cloudscraper.CloudflareLoopProtection:
print("Too many challenge attempts - infinite loop detected")
except cloudscraper.CloudflareV3Error:
print("v3 JavaScript VM challenge failed")
except cloudscraper.CloudflareTurnstileError:
print("Turnstile challenge failed")
except cloudscraper.CloudflareCaptchaProvider:
print("CAPTCHA challenge detected but no solver configured")
except cloudscraper.CloudflareSolveError:
print("General challenge solving error")For advanced users who need to detect challenges manually:
response = scraper.get('https://example.com')
# Manual challenge detection
if cloudscraper.CloudflareTurnstile.is_Turnstile_Challenge(response):
print("Turnstile detected")
elif cloudscraper.CloudflareV3.is_V3_Challenge(response):
print("v3 challenge detected")
elif cloudscraper.CloudflareV2.is_V2_Challenge(response):
print("v2 JS challenge detected")
elif cloudscraper.CloudflareV2.is_V2_Captcha_Challenge(response):
print("v2 CAPTCHA challenge detected")
elif cloudscraper.Cloudflare.is_Challenge_Request(response):
print("v1 challenge detected")Use request hooks to monitor challenge solving:
def pre_challenge_hook(scraper, method, url, *args, **kwargs):
print(f"About to solve challenge for {url}")
return method, url, args, kwargs
def post_challenge_hook(scraper, response):
if response.status_code == 200:
print("Challenge solved successfully")
return response
scraper = cloudscraper.create_scraper(
requestPreHook=pre_challenge_hook,
requestPostHook=post_challenge_hook
)Install with Tessl CLI
npx tessl i tessl/pypi-cloudscraper