CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-cloudscraper

Enhanced Python module to bypass Cloudflare's anti-bot page with support for v1, v2, v3 challenges, Turnstile, proxy rotation, and stealth mode.

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

challenge-handling.mddocs/

Challenge Handling

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.

Capabilities

Cloudflare v1 (Legacy) Challenges

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
        """

Usage Examples

# 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")

Cloudflare v2 Challenges

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
        """

Usage Examples

# 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)

Cloudflare v3 JavaScript VM Challenges

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
        """

Usage Examples

# 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)

Cloudflare Turnstile Challenges

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
        """

Usage Examples

# 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)

Challenge Detection and Priority

CloudScraper automatically detects and handles challenges in priority order:

  1. Turnstile challenges (highest priority)
  2. v3 JavaScript VM challenges
  3. v2 JavaScript and CAPTCHA challenges
  4. v1 legacy challenges (lowest priority)
# 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
)

Challenge Solving Configuration

JavaScript Interpreter Selection

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')

Challenge Timing

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
)

Debug Mode for Challenges

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"

Error Handling

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")

Advanced Challenge Handling

Custom Challenge Detection

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")

Challenge Hooks

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

docs

captcha-solving.md

challenge-handling.md

core-scraper.md

index.md

javascript-interpreters.md

proxy-management.md

stealth-mode.md

user-agent.md

tile.json