Repository navigation
CDP Executors
While standard Selenium provides high-level commands, many advanced features (like detailed network interception, precise emulation, or performance monitoring) are only available via the Chrome DevTools Protocol (CDP).
The executors package provides a unified bridge to CDP, handling the complexity of protocol versioning and asynchronous execution.
CDP changes as Chrome/Chromium updates. A command that works in version 140 might behave differently or be renamed in version 144.
osn-selenium solves this by providing version-specific executors. The library currently supports a range from v140 to v144. Accessing them is as simple as calling the corresponding property on the cdp object:
from osn_selenium.webdrivers.sync.chrome import ChromeWebDriver
driver = ChromeWebDriver(webdriver_path="./chromedriver")
# Accessing version 144 domains
executor = driver.cdp.v144The framework uses Lazy Loading for CDP modules. It does not import version-specific logic until you actually call it. This keeps the initial library memory footprint low and prevents errors if you don't have all versioned packages installed.
To keep the core library lightweight, versioned CDP logic is stored in separate external packages (e.g., osn-selenium-cdp).
If you attempt to access a version that is not installed on your system, the executor will raise a CDPPackageError. This error is helpful—it checks GitHub for the existence of that version and provides the exact pip command to fix the issue:
Error Example:
CDPpackage for v144 is not installed. Fix: Run the following command: pip install git+https://github.com/oddshellnick/osn-selenium-cdp.git@v144
The CDP Executor adapts to the architecture of your driver.
In synchronous drivers, CDP commands are executed immediately through a bridge that interacts with the underlying Selenium driver.
from osn_selenium.webdrivers.sync.chrome import ChromeWebDriver
driver = ChromeWebDriver(webdriver_path="./chromedriver")
# Sync driver example
driver.cdp.v144.page.navigate(url="https://example.com")In Trio-based drivers, every CDP call is automatically wrapped in a thread-safe task. You must use the await keyword, and the executor ensures that the command respects the trio.Lock and CapacityLimiter of the driver instance.
from osn_selenium.webdrivers.sync.chrome import ChromeWebDriver
driver = ChromeWebDriver(webdriver_path="./chromedriver")
# Trio driver example
await driver.cdp.v144.emulation.set_geolocation_override(
latitude=48.8584,
longitude=2.2945,
accuracy=100
)In trio_bidi drivers, the executor is powered by the BiDi Mapping. Calls are routed to the CDPExecutor which uses the connection pool to send goog:cdp.sendCommand via the WebSocket. This is highly efficient as it bypasses the HTTP overhead of the ChromeDriver entirely.
from osn_selenium.webdrivers.trio_bidi.chrome import ChromeWebDriver
driver = ChromeWebDriver(webdriver_path="./chromedriver")
# Direct WebSocket Command
await driver.cdp.v144.target.get_targets()Under the hood, the executors use a "Bridge" function (get_cdp_executor_bridge). This bridge performs several critical tasks:
- Unwrapping: It extracts raw Selenium objects from your Python wrappers before sending the command.
-
Execution: It calls the native
execute_cdp_cmdmethod of the WebDriver. -
Wrapping: It takes the selenium result from the browser and wraps any returned objects back into the framework's
SyncorTrioThreadmodels.
Here is how you would use the CDP Executor to simulate a slow 3G connection:
from osn_selenium.webdrivers.sync.chrome import ChromeWebDriver
driver = ChromeWebDriver(webdriver_path="./chromedriver")
# Enable network domain
driver.cdp.v144.network.enable()
# Set throttling conditions
driver.cdp.v144.network.emulate_network_conditions(
offline=False,
latency=100, # 100ms
download_throughput=750 * 1024, # 750kb/s
upload_throughput=250 * 1024, # 250kb/s
connection_type="cellular3g"
)All officially maintained and pre-generated CDP packages can be found in the following repository:
🔗 osn-selenium-cdp
You can check available branches (v140, v141, etc.) to see which protocol versions are ready for installation.
If you are using a very new or highly specific version of Chromium that isn't yet available in the official repository, you can generate your own CDP wrapper package using:
🔗 osn-selenium-package-parser (it will be public soon)
This tool parses the Chrome protocol definition and creates a compatible Python package structure that integrates seamlessly with the framework.
Every WebDriver class in the framework (Chrome, Edge, Yandex) provides two specific parameters to manage custom or local CDP packages without requiring them to be installed in your global site-packages:
-
cdp_versioned_packages_paths: A mapping (dictionary) where the key is the version integer (e.g.,145) and the value is the local filesystem path to your generated package. -
ignore_cdp_version_package_missing: A boolean flag (defaultTrue). If set toFalse, the library will immediately raise an error if the requested CDP version is not found, rather than attempting to fall back or ignore it.
Example of using a local custom CDP package:
from osn_selenium.webdrivers.sync.chrome import ChromeWebDriver
driver = ChromeWebDriver(
webdriver_path="./chromedriver",
cdp_versioned_packages_paths={
145: "/home/user/my_custom_cdp_v145"
},
ignore_cdp_version_package_missing=False
)This mechanism uses a custom MetaPathFinder (the CDP Import Hook) to redirect Python's import system to your specified local directory whenever driver.cdp.v145 is accessed.