Nodriver
Nodriver is a Python library for browser automation and web scraping, acting as the official successor to Undetected-Chromedriver. It communicates directly with browsers using the Chrome DevTools Protocol, eliminating the need for Selenium or WebDriver binaries, which significantly boosts performance and resistance against anti-bot systems. It is fully asynchronous and focuses on usability and quick prototyping. The current version is 0.48.1, and it seems to have a regular update cadence given the recent articles and version number.
Common errors
-
ImportError: cannot import name 'nodriver' from 'nodriver'
cause Your Python script file is named `nodriver.py`, causing a conflict with the installed package.fixRename your Python script file to anything other than `nodriver.py` (e.g., `main.py`, `scraper.py`). -
aiohttp.client_exceptions.ClientConnectorError: Cannot connect to host localhost:<port> [Connect call failed ('127.0.0.1', <port>)]cause Nodriver failed to establish a connection to the Chrome DevTools Protocol. This often occurs if Chrome is already running and locking its profile, if Chrome takes too long to launch, or if background Chrome processes are interfering.fixTry killing any lingering Chrome processes, increase the startup timeout for `nodriver.start(timeout=...)`, or configure a dedicated user data directory for `nodriver` to prevent profile locking issues via `nodriver.Config(user_data_dir='path/to/new_profile')`. -
nodriver.ProtocolException: No node with given id found
cause A Chrome DevTools Protocol command failed because a specified element (node_id, selector) could not be found or was invalid at the time of the command execution.fixEnsure that the element you are trying to interact with exists on the page when the command is called. Use `await page.wait_for_selector('selector')` or appropriate waits before interaction, and double-check your selectors or node IDs. -
FileNotFoundError: [Errno 2] No such file or directory: '/invalid/path/to/chrome'
cause Nodriver could not find the Chrome/Chromium executable at the specified `browser_executable_path` in `Config` or in common system locations.fixVerify that Chrome/Chromium is installed and accessible. If you've provided a custom path, ensure it's correct. If not provided, ensure Chrome is installed in a default location `nodriver` can detect. -
RuntimeError: Cannot run Browser.get() outside of async context
cause Nodriver functions that involve browser interaction (like `browser.get()` or `uc.start()`) must be called within an `async` function and executed via an `asyncio` event loop.fixEnsure all `nodriver` calls are correctly `await`ed within `async` functions, and the main entry point is executed using `nodriver.loop().run_until_complete(main())`.
Warnings
- gotcha Naming your Python script `nodriver.py` can cause an `ImportError` because Python may try to import your local file instead of the installed package.
- gotcha Using `asyncio.run()` directly to execute your main asynchronous function can sometimes lead to unexpected behavior with `nodriver`'s event loop management.
- breaking Headless mode (`headless=True`) can sometimes trigger anti-bot detection or lead to `ERR_HTTP2_PROTOCOL_ERROR` on certain websites, especially compared to headed mode.
- gotcha Nodriver can fail to connect to Chrome (e.g., `ClientConnectorError`) if the Chrome profile is locked by another process or if the debugging port is slow to open, particularly on macOS or when using existing profiles.
- gotcha The `tab.cf_verify()` method for Cloudflare bypass only works when the browser is NOT started in 'expert' mode and requires the `opencv-python` package to be installed.
Install
-
pip install nodriver
Imports
- nodriver
import nodriver
- ProtocolException
from nodriver import ProtocolException
- Config
from nodriver import Config
- cdp
from nodriver import cdp
Quickstart
import nodriver
import asyncio
async def main():
browser = await nodriver.start(headless=True)
page = await browser.get('https://example.com')
print(f"Page title: {await page.get_title()}")
await page.close()
await browser.stop()
if __name__ == '__main__':
nodriver.loop().run_until_complete(main())