Selenium Wire

repository·master·Indexed 24 days ago

https://github.com/wkeeling/selenium-wire

An extension for Selenium's Python bindings that enables developers to inspect, intercept, and modify underlying HTTP/HTTPS and WebSocket requests and responses made by the browser. It provides tools for request/response interception, mocking responses, blocking requests, and configuring upstream proxies.

Tokens
4.6K
Snippets
17
Records
23
Agent score
34%

What's inside selenium-wire

  1. Intercept and modify requests and responses

    master

    Selenium Wire allows you to modify network traffic on the fly using interceptors.

    • Request Interceptor: A function that accepts a single argument (request). Set it via driver.request_interceptor.
    • Response Interceptor: A function that accepts two arguments (request, response). Set it via driver.response_interceptor.

    Important Patterns:

    • Replacing Headers: Since request.headers allows duplicates, always use del request.headers['header-name'] before setting a new value to ensure you are replacing rather than appending.
    • Updating Parameters: Request parameters are held in a regular dictionary. To update them, you must read the dictionary, modify it, and write it back to request.params.
    • Updating JSON Bodies: For POST requests with JSON, you must decode the request.body (bytes) to a string, parse it, modify it, and then re-encode it back to bytes. Remember to update the Content-Length header manually after modifying the body.
    def interceptor(request):
        params = request.params
        params['foo'] = 'bar'
        request.params = params
    
    driver.request_interceptor = interceptor
    driver.get(...)
    
    # To unset an interceptor:
    del driver.request_interceptor
    del driver.response_interceptor
  2. Configure OpenSSL for HTTPS decryption

    master

    Selenium Wire requires OpenSSL to decrypt HTTPS requests. You can check your installation with openssl version. If not installed, use the following commands:

    Linux (apt):

    sudo apt install openssl

    Linux (RPM):

    sudo yum install openssl

    Linux (Alpine):

    sudo apk add openssl

    MacOS:

    brew install openssl

    Windows: No installation is required.

  3. Use custom SSL certificates

    master

    Selenium Wire uses its own root certificate to decrypt HTTPS traffic. To avoid the "Not Secure" browser warning, you can manually install the Selenium Wire CA certificate into your browser's "Authorities" section.

    If you prefer to use your own root certificate, provide the paths to your certificate and private key using the ca_cert and ca_key options. Note: If you use your own certificate, you must manually delete Selenium Wire's temporary storage folder to clear cached certificates.

    options = {
        'ca_cert': '/path/to/ca.crt',
        'ca_key': '/path/to/ca.key'
    }
    driver = webdriver.Chrome(seleniumwire_options=options)
  4. Configure upstream proxies

    master

    You can configure Selenium Wire to use an upstream proxy server by passing a proxy dictionary to the seleniumwire_options argument of the webdriver.

    Supported configurations include:

    • HTTP/HTTPS Proxies: Specify URLs for http and https schemes.
    • Basic Authentication: Include credentials directly in the URL (e.g., https://user:pass@host:port).
    • Custom Authorization: Use the custom_authorization key within the proxy dictionary to provide non-Basic authentication headers, such as Bearer tokens.
    • SOCKS Proxies: Use socks5, socks4, or socks5h schemes. Use socks5h to perform DNS resolution on the proxy server instead of the client.

    Alternatively, you can set the HTTP_PROXY, HTTPS_PROXY, and NO_PROXY environment variables.

    # HTTP Proxy with Basic Auth
    options = {
        'proxy': {
            'http': 'http://192.168.10.100:8888',
            'https': 'https://user:pass@192.168.10.100:8888',
            'no_proxy': 'localhost,127.0.0.1'
        }
    }
    driver = webdriver.Chrome(seleniumwire_options=options)
    
    # SOCKS Proxy
    options = {
        'proxy': {
            'http': 'socks5://user:pass@192.168.10.100:8888',
            'https': 'socks5://user:pass@192.168.10.100:8888',
            'no_proxy': 'localhost,127.0.0.1'
        }
    }
    driver = webdriver.Chrome(seleniumwire_options=options)
    
    # Custom Proxy-Authorization (e.g., Bearer token)
    options = {
        'proxy': {
            'https': 'https://192.168.10.100:8888',
            'custom_authorization': 'Bearer mytoken123'
        }
    }
  5. Integrate with undetected-chromedriver to avoid bot detection

    master

    Selenium Wire can integrate with undetected-chromedriver to help prevent triggering anti-bot measures. To use this, install the package and import from seleniumwire.undetected_chromedriver instead of the standard selenium modules.

    pip install undetected-chromedriver
    import seleniumwire.undetected_chromedriver as uc
    
    chrome_options = uc.ChromeOptions()
    
    driver = uc.Chrome(
        options=chrome_options,
        seleniumwire_options={}
    )
  6. Limit request capture

    master

    To improve performance or reduce overhead, you can restrict what Selenium Wire captures using several methods:

    1. driver.scopes: A list of regular expressions. Only URLs matching these patterns will be captured. Unmatched requests still pass through the proxy but are not stored.
    2. seleniumwire_options['disable_capture']: Disables request interception and storage entirely. Interceptors will not execute.
    3. seleniumwire_options['exclude_hosts']: A list of hostnames that will bypass the Selenium Wire proxy entirely, going direct from the browser to the server.
    4. request.abort(): Blocking specific request types (like images) via an interceptor to speed up page loads.
    # Using scopes
    driver.scopes = [
        '.*stackoverflow.*',
        '.*github.*'
    ]
    
    # Using exclude_hosts
    options = {
        'exclude_hosts': ['host1.com', 'host2.com']
    }
    driver = webdriver.Chrome(seleniumwire_options=options)
    
    # Disabling capture
    options = {
        'disable_capture': True
    }
    driver = webdriver.Chrome(seleniumwire_options=options)
  7. Configure request storage location and mode

    master

    Selenium Wire stores captured requests/responses in a .seleniumwire sub-folder within the system temp directory by default. You can customize this behavior via seleniumwire_options:

    • request_storage_base_dir: Set a custom base directory for the .seleniumwire folder.
    • request_storage: Set to 'memory' to store requests in RAM instead of on disk. This is useful for short-lived environments like Docker.
    • request_storage_max_size: When using 'memory' mode, use this to limit the number of requests stored. Once the limit is reached, older requests are discarded.
    # Custom disk storage
    options = {
        'request_storage_base_dir': '/my/storage/folder'
    }
    driver = webdriver.Chrome(seleniumwire_options=options)
    
    # In-memory storage with size limit
    options = {
        'request_storage': 'memory',
        'request_storage_max_size': 100
    }
    driver = webdriver.Chrome(seleniumwire_options=options)
  8. Mock a response

    master

    Use request.create_response() to intercept a request and return a custom response without ever contacting the remote server.

    def interceptor(request):
        if request.url == 'https://server.com/some/path':
            request.create_response(
                status_code=200,
                headers={'Content-Type': 'text/html'},  # Optional headers dictionary
                body='<html>Hello World!</html>'  # Optional body
            )
    
    driver.request_interceptor = interceptor
    driver.get(...)
  9. Add a response header

    master

    Use a response interceptor to inject headers into responses received from the server.

    def interceptor(request, response):  # A response interceptor takes two args
        if request.url == 'https://server.com/some/path':
            response.headers['New-Header'] = 'Some Value'
    
    driver.response_interceptor = interceptor
    driver.get(...)
  10. Block a request

    master

    Use request.abort() within an interceptor to block a request and return an immediate response (default status is 403 Forbidden).

    def interceptor(request):
        # Block PNG, JPEG and GIF images
        if request.path.endswith(('.png', '.jpg', '.gif')):
            request.abort()
    
    driver.request_interceptor = interceptor
    driver.get(...)
  11. Add a request header

    master

    Use a request interceptor to inject new headers into every outgoing request.

    def interceptor(request):
        request.headers['New-Header'] = 'Some Value'
    
    driver.request_interceptor = interceptor
    driver.get(...)
    
    # All requests will now contain New-Header