### Initial Python Script Setup Source: https://github.com/cdpdriver/zendriver/blob/main/docs/tutorials/api-responses.md Sets up the initial Python script for the tutorial. This typically involves importing necessary libraries. ```python from playwright.sync_api import Page, expect def test_api_response(page: Page): page.goto("https://cdpdriver.github.io/examples/api-request.html") # ... rest of the test ``` -------------------------------- ### Basic Zendriver Usage Example Source: https://github.com/cdpdriver/zendriver/blob/main/README.md Example of visiting a website, saving a screenshot, and stopping the browser. Requires asyncio. ```python import asyncio import zendriver as zd async def main(): browser = await zd.start() page = await browser.get("https://www.browserscan.net/bot-detection") await page.save_screenshot("browserscan.png") await browser.stop() if __name__ == "__main__": asyncio.run(main()) ``` -------------------------------- ### Initial Setup for Account Creation Tutorial Source: https://github.com/cdpdriver/zendriver/blob/main/docs/tutorials/account-creation.md Sets up the necessary environment for the account creation tutorial. This script is typically imported or included at the beginning of the tutorial's execution. ```python # --8<-- "docs/tutorials/tutorial-code/account-creation-1.py" ``` -------------------------------- ### Changelog Entry Example Source: https://github.com/cdpdriver/zendriver/blob/main/CONTRIBUTING.md An example of how to format an entry in the CHANGELOG.md file. Add your changes under the appropriate category in the `[Unreleased]` section. ```markdown ## [Unreleased] ### Fixed - Fixed a bug with caused the browser to crash @yourgithubhandle ### Added ### Changed ### Removed ``` -------------------------------- ### Initial Setup for Infinite Scrolling Source: https://github.com/cdpdriver/zendriver/blob/main/docs/tutorials/infinite-scrolling.md This initial script sets up the basic structure but does not include waiting logic, resulting in an empty list of cards. ```python # Import necessary libraries from cdpdriver import CDPDRIVER # Initialize CDPDRIVER driver = CDPDRIVER() # Navigate to the target page driver.get("https://cdpdriver.github.io/examples/scrollable-cards.html") # Attempt to find cards without waiting cards = driver.find_elements_by_css_selector(".card") print(f"Found {len(cards)} cards initially.") # Close the browser driver.quit() ``` -------------------------------- ### Install Zendriver using pip Source: https://github.com/cdpdriver/zendriver/blob/main/README.md Install the Zendriver package using pip or other package managers. ```sh pip install zendriver # or uv add zendriver, poetry add zendriver, etc. ``` -------------------------------- ### Advanced Zendriver Usage: Multiple Tabs and Windows Source: https://github.com/cdpdriver/zendriver/blob/main/docs/quickstart.md Demonstrates opening multiple tabs and windows, interacting with elements by flashing them, scrolling, reloading pages, and closing tabs. This example requires careful management of asynchronous operations. ```python import asyncio import zendriver as zd async def main(): browser = await zd.start() page = await browser.get('https://zendriver.dev/') elems = await page.select_all('*[src]') for elem in elems: await elem.flash() page2 = await browser.get('https://twitter.com', new_tab=True) page3 = await browser.get('https://github.com/ultrafunkamsterdam/nodriver', new_window=True) for p in (page, page2, page3): await p.bring_to_front() await p.scroll_down(200) await p # wait for events to be processed await p.reload() if p != page3: await p.close() if __name__ == '__main__': asyncio.run(main()) ``` -------------------------------- ### Zendriver Start with Custom Options Source: https://github.com/cdpdriver/zendriver/blob/main/docs/quickstart.md Initiate a Zendriver browser session with custom configurations such as headless mode, user data directory, specific browser executable, arguments, and language settings. Note that 'user_data_dir' prevents automatic cleanup. ```python import zendriver as zd browser = await zd.start( headless=False, user_data_dir="/path/to/existing/profile", # by specifying it, it won't be automatically cleaned up when finished browser_executable_path="/path/to/some/other/browser", browser_args=['--some-browser-arg=true', '--some-other-option'], lang="en-US" # this could set iso-language-code in navigator, not recommended to change ) tab = await browser.get('https://somewebsite.com') ``` -------------------------------- ### Automate Browser Tasks with Zendriver Source: https://github.com/cdpdriver/zendriver/blob/main/docs/quickstart.md This snippet shows a complete workflow for browser automation using Zendriver. It covers starting a browser, navigating, taking screenshots, uploading files, and extracting information. ```python import asyncio from pathlib import Path import zendriver as zd DELAY = 2 async def main(): browser = await zd.start() tab = await browser.get("https://imgur.com") # now we first need an image to upload, lets make a screenshot of the project page save_path = Path("screenshot.jpg").resolve() # create new tab with the project page temp_tab = await browser.get( "https://github.com/ultrafunkamsterdam/undetected-chromedriver", new_tab=True ) # wait page to load await temp_tab # save the screenshot to the previously declared path of screenshot.jpg (which is just current directory) await temp_tab.save_screenshot(save_path) # done, discard the temp_tab await temp_tab.close() # accept goddamn cookies # the best_match flag will filter the best match from # matching elements containing "consent" and takes the # one having most similar text length consent = await tab.find("Consent", best_match=True) await consent.click() # shortcut await (await tab.find("new post", best_match=True)).click() file_input = await tab.select("input[type=file]") await file_input.send_file(save_path) # since file upload takes a while , the next buttons are not available yet await tab.wait(DELAY) # wait until the grab link becomes clickable, by waiting for the toast message await tab.select(".Toast-message--check") # this one is tricky. we are trying to find a element by text content # usually. the text node itself is not needed, but it's enclosing element. # in this case however, the text is NOT a text node, but an "placeholder" attribute of a span element. # so for this one, we use the flag return_enclosing_element and set it to False title_field = await tab.find("give your post a unique title", best_match=True) print(title_field) await title_field.send_keys("undetected zendriver") grab_link = await tab.find("grab link", best_match=True) await grab_link.click() # there is a delay for the link sharing popup. # let's pause for a sec await tab.wait(DELAY) # get inputs of which the value starts with http input_thing = await tab.select("input[value^=https]") my_link = input_thing.attrs.value print(my_link) await browser.stop() if __name__ == "__main__": asyncio.run(main()) ``` -------------------------------- ### Tab.set_user_agent() Source: https://context7.com/cdpdriver/zendriver/llms.txt Overrides user agent, language, and platform for the current tab session at the CDP level. It's generally recommended to set the user agent globally when starting the browser using `zd.start(user_agent=...)` for most use cases. ```APIDOC ## `Tab.set_user_agent()` — Override user agent per-tab Overrides `navigator.userAgent`, `navigator.language`, and `navigator.platform` at the CDP level for the current tab session. For most use cases, prefer passing `user_agent` to `zd.start()` so it applies globally before the browser starts. ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **user_agent** (string) - Required - The user agent string to set. - **accept_language** (string) - Optional - The accept language string to set. - **platform** (string) - Optional - The platform string to set. ### Request Example ```python await tab.set_user_agent( user_agent="Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) " "AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1", accept_language="en-US,en;q=0.9", platform="iPhone", ) ``` ### Response #### Success Response (200) None (operation is asynchronous and returns no data upon success) #### Response Example None ``` -------------------------------- ### Intercept Network Events with Tab.expect_request() / Tab.expect_response() Source: https://context7.com/cdpdriver/zendriver/llms.txt Async context managers that register handlers for network events, matching by URL regex. Use await expectation.value to get the matched event and await expectation.response_body to retrieve the response body. ```python import asyncio import re import zendriver as zd async def main(): browser = await zd.start() tab = await browser.get("https://httpbin.org") # Capture an API response matching a URL pattern async with tab.expect_response(re.compile(r".*httpbin\.org/get.*$?")) as resp_ex: await tab.get("https://httpbin.org/get") response = await resp_ex.response body, is_base64 = await resp_ex.response_body print(response.status) # 200 print(body[:200]) # {"args": {}, "headers": {...}, ...} # Capture a request before it is sent async with tab.expect_request("https://httpbin.org/post") as req_ex: await tab.evaluate( "fetch('https://httpbin.org/post', {method:'POST', body:'hello'})" ) request = await req_ex.request print(request.method, request.url) # POST https://httpbin.org/post await browser.stop() asyncio.run(main()) ``` -------------------------------- ### Manage Browser Cookies with CookieJar Source: https://context7.com/cdpdriver/zendriver/llms.txt Use `browser.cookies` to get, set, save, load, and clear cookies. Cookies can be filtered by domain when saving or loading. ```python import asyncio import zendriver as zd from zendriver import cdp async def main(): browser = await zd.start() await browser.get("https://example.com") # Read all cookies cookies = await browser.cookies.get_all() for c in cookies: print(c.name, c.value, c.domain) # Read in requests-compatible format req_cookies = await browser.cookies.get_all(requests_cookie_format=True) # Set cookies manually await browser.cookies.set_all([ cdp.network.CookieParam(name="session", value="abc123", domain="example.com") ]) # Persist session to disk (regex filter: only "example.com" cookies) await browser.cookies.save(".session.dat", pattern="example.com") # Later: restore await browser.cookies.load(".session.dat", pattern="example.com") # Wipe all cookies await browser.cookies.clear() await browser.stop() asyncio.run(main()) ``` -------------------------------- ### Launch a browser instance with zd.start() Source: https://context7.com/cdpdriver/zendriver/llms.txt Use `zd.start()` for a minimal or fully configured browser launch. It auto-detects browsers by default and supports options for headless mode, user data persistence, custom executables, and arguments. ```python import asyncio import zendriver as zd async def main(): # Minimal: auto-detect browser, headed mode, fresh temp profile browser = await zd.start() # Fully configured browser = await zd.start( headless=True, browser="chrome", # "chrome", "brave", or "auto" user_data_dir="/tmp/my-profile", # persist cookies/profile browser_executable_path="/usr/bin/google-chrome", browser_args=["--window-size=1920,1080"], sandbox=True, # set False when running as root lang="en-US", user_agent="Mozilla/5.0 (compatible; MyBot/1.0)", ) page = await browser.get("https://example.com") print(page) # ] [page] [url: https://example.com]> await browser.stop() asyncio.run(main()) ``` -------------------------------- ### zd.start() Source: https://context7.com/cdpdriver/zendriver/llms.txt Launches a browser instance and connects to it via the Chrome DevTools Protocol. This is a top-level convenience function that creates a Browser instance with sensible defaults if no arguments are provided. It returns an awaitable Browser object. ```APIDOC ## zd.start() — Launch a browser instance Top-level convenience function that creates a `Browser` instance, launching a local Chromium/Chrome/Brave process and connecting over CDP. All parameters are optional; calling it bare applies sensible defaults. Returns an awaitable `Browser`. ### Method GET ### Endpoint / ### Parameters #### Query Parameters - **headless** (boolean) - Optional - Whether to run the browser in headless mode. - **browser** (string) - Optional - Specifies the browser to use ('chrome', 'brave', or 'auto'). - **user_data_dir** (string) - Optional - Path to a directory to persist browser profile and cookies. - **browser_executable_path** (string) - Optional - Explicit path to the browser executable. - **browser_args** (list of strings) - Optional - Additional command-line arguments for the browser. - **sandbox** (boolean) - Optional - Whether to enable the browser sandbox (set to False when running as root). - **lang** (string) - Optional - Language setting for the browser. - **user_agent** (string) - Optional - Custom User-Agent string for the browser. ### Request Example ```python import asyncio import zendriver as zd async def main(): # Minimal: auto-detect browser, headed mode, fresh temp profile browser = await zd.start() # Fully configured browser = await zd.start( headless=True, browser="chrome", # "chrome", "brave", or "auto" user_data_dir="/tmp/my-profile", # persist cookies/profile browser_executable_path="/usr/bin/google-chrome", browser_args=["--window-size=1920,1080"], sandbox=True, # set False when running as root lang="en-US", user_agent="Mozilla/5.0 (compatible; MyBot/1.0)", ) page = await browser.get("https://example.com") print(page) # ] [page] [url: https://example.com]> await browser.stop() asyncio.run(main()) ``` ### Response #### Success Response (200) - **Browser** (object) - An awaitable Browser object representing the launched browser instance. ``` -------------------------------- ### Browser.cookies Source: https://context7.com/cdpdriver/zendriver/llms.txt Manages cookies across all tabs using a CookieJar. Supports getting, setting, saving, loading, and clearing cookies. ```APIDOC ## Browser.cookies ### Description Manages cookies across all tabs using a CookieJar. Supports getting, setting, saving, loading, and clearing cookies. ### Methods - `get_all()`: Retrieves all cookies, optionally in requests-compatible format. - `set_all(cookies)`: Sets all provided cookies. - `save(filename, pattern)`: Saves cookies to a file, optionally filtered by a pattern. - `load(filename, pattern)`: Loads cookies from a file, optionally filtered by a pattern. - `clear()`: Clears all cookies. ### Example Usage ```python import asyncio import zendriver as zd from zendriver import cdp async def main(): browser = await zd.start() await browser.get("https://example.com") # Read all cookies cookies = await browser.cookies.get_all() for c in cookies: print(c.name, c.value, c.domain) # Read in requests-compatible format req_cookies = await browser.cookies.get_all(requests_cookie_format=True) # Set cookies manually await browser.cookies.set_all([ cdp.network.CookieParam(name="session", value="abc123", domain="example.com") ]) # Persist session to disk (regex filter: only "example.com" cookies) await browser.cookies.save(".session.dat", pattern="example.com") # Later: restore await browser.cookies.load(".session.dat", pattern="example.com") # Wipe all cookies await browser.cookies.clear() await browser.stop() asyncio.run(main()) ``` ``` -------------------------------- ### Create a Browser instance with Browser.create() Source: https://context7.com/cdpdriver/zendriver/llms.txt Use `zd.Browser.create()` with a pre-built `Config` object for more granular control over browser settings. This method also registers an `atexit` handler for clean browser shutdown. ```python import asyncio import zendriver as zd from zendriver import Config async def main(): config = Config( headless=False, disable_webrtc=True, # prevent IP leaks (default True) disable_webgl=False, browser_connection_timeout=0.5, browser_connection_max_tries=15, ) config.add_argument("--mute-audio") browser = await zd.Browser.create(config) tab = await browser.get("https://example.com") await browser.stop() asyncio.run(main()) ``` -------------------------------- ### Complete Account Creation and Login Script Source: https://github.com/cdpdriver/zendriver/blob/main/docs/tutorials/account-creation.md Combines the account creation and login functions into a single script to demonstrate the full workflow. This script automates both signing up and logging in. ```python # --8<-- "docs/tutorials/tutorial-code/account-creation-2.py" ``` -------------------------------- ### Configure Browser Launch with `Config` Object Source: https://context7.com/cdpdriver/zendriver/llms.txt Shows how to use the `Config` object to set launch parameters, add custom Chromium flags, and load extensions. The `Config` object can be reused across multiple `Browser.create()` calls. ```python import asyncio import zendriver as zd from zendriver import Config async def main(): config = Config( headless=True, sandbox=False, # required when running as root (Linux) lang="de-DE", user_agent="CustomAgent/1.0", disable_webrtc=True, # prevent WebRTC IP leaks (default True) disable_webgl=True, # block WebGL fingerprinting browser_connection_timeout=0.5, browser_connection_max_tries=20, ) # Add arbitrary Chromium flags config.add_argument("--disable-notifications") config.add_argument("--blink-settings=imagesEnabled=false") # Load an unpacked extension config.add_extension("/path/to/my-extension/") # Connect to an already-running debuggable Chrome config.host = "127.0.0.1" config.port = 9222 # existing --remote-debugging-port browser = await zd.Browser.create(config) tab = await browser.get("https://example.com") await browser.stop() asyncio.run(main()) ``` -------------------------------- ### Browser.create() Source: https://context7.com/cdpdriver/zendriver/llms.txt An alternative asynchronous class-method constructor for creating a `Browser` instance, particularly useful when a pre-configured `Config` object is preferred. It accepts the same keyword arguments as `zd.start()` and automatically registers an `atexit` handler for clean browser shutdown. ```APIDOC ## Browser.create() — Async class-method constructor Alternative to `zd.start()` when a pre-built `Config` object is preferred. Accepts the same keyword arguments. Registers an `atexit` handler to cleanly stop the browser. ### Method POST ### Endpoint /browser/create ### Parameters #### Request Body - **config** (Config object) - A pre-built Config object with browser settings. - **headless** (boolean) - Optional - Whether to run the browser in headless mode. - **disable_webrtc** (boolean) - Optional - Whether to disable WebRTC (default True). - **disable_webgl** (boolean) - Optional - Whether to disable WebGL. - **browser_connection_timeout** (float) - Optional - Timeout for browser connection attempts. - **browser_connection_max_tries** (integer) - Optional - Maximum number of retries for browser connection. ### Request Example ```python import asyncio import zendriver as zd from zendriver import Config async def main(): config = Config( headless=False, disable_webrtc=True, # prevent IP leaks (default True) disable_webgl=False, browser_connection_timeout=0.5, browser_connection_max_tries=15, ) config.add_argument("--mute-audio") browser = await zd.Browser.create(config) tab = await browser.get("https://example.com") await browser.stop() asyncio.run(main()) ``` ### Response #### Success Response (200) - **Browser** (object) - A Browser instance created with the provided configuration. ``` -------------------------------- ### Basic Browser Automation with Zendriver Source: https://github.com/cdpdriver/zendriver/blob/main/docs/quickstart.md Open a browser, navigate to a URL, scrape HTML content, and take a screenshot. Ensure asyncio is imported for asynchronous operations. ```python import asyncio import zendriver as zd async def main(): browser = await zd.start() page = await browser.get('https://example.com') # get HTML content of the page as a string content = await page.get_content() # save a screenshot await page.save_screenshot() # close the browser window await browser.stop() if __name__ == '__main__': asyncio.run(main()) ``` -------------------------------- ### Tab.download_file() Source: https://context7.com/cdpdriver/zendriver/llms.txt Initiates a file download by simulating a JavaScript `fetch` request and an anchor tag click. The downloaded file is saved to a specified directory or a default location. ```APIDOC ## `Tab.download_file()` — Download a file by URL Triggers a file download by injecting a JavaScript `fetch` + blob anchor click. The download is saved to the directory set via `tab.set_download_path()` (or a default `./downloads/` folder). ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **url** (string) - Required - The URL of the file to download. - **filename** (string) - Optional - The desired name for the downloaded file. If not provided, the original filename from the URL will be used. ### Request Example ```python # Set download directory first await tab.set_download_path("/tmp/downloads") # Download a specific file await tab.download_file( "https://example.com/report.pdf", filename="my_report.pdf" ) # Download all linked files from a page urls = await tab.get_all_urls() pdf_urls = [u for u in urls if u.endswith(".pdf")] for url in pdf_urls: await tab.download_file(url) ``` ### Response #### Success Response (200) None (operation is asynchronous and returns no data upon success) #### Response Example None ``` -------------------------------- ### Create New Account Function Source: https://github.com/cdpdriver/zendriver/blob/main/docs/tutorials/account-creation.md Defines a function to click the sign-up link, fill out the new account form, and submit it. This is used for automating the account creation process. ```python # --8<-- "docs/tutorials/tutorial-code/account-creation-2.py:7:30" ``` -------------------------------- ### Config Source: https://context7.com/cdpdriver/zendriver/llms.txt The `Config` object holds all browser launch parameters and can be reused as a template. It allows for custom Chromium flags and loading unpacked extensions. ```APIDOC ## Config ### Description `Config` holds all launch parameters and can be reused as a template across multiple `Browser.create()` calls. Use `add_argument()` for custom Chromium flags and `add_extension()` to load unpacked extensions or `.crx` files. ### Initialization `Config(headless=True, sandbox=False, lang='en-US', user_agent=None, disable_webrtc=True, disable_webgl=True, browser_connection_timeout=None, browser_connection_max_tries=None, host=None, port=None)` ### Methods #### `add_argument(argument: str)` Adds an arbitrary Chromium flag as a string. #### `add_extension(path: str)` Loads an unpacked extension or a `.crx` file from the specified path. ### Properties - **headless**: (bool) - Whether to run the browser in headless mode. Defaults to True. - **sandbox**: (bool) - Whether to enable the sandbox. Defaults to False (required when running as root on Linux). - **lang**: (str) - The language for the browser locale. Defaults to 'en-US'. - **user_agent**: (str) - A custom user agent string. - **disable_webrtc**: (bool) - Whether to disable WebRTC to prevent IP leaks. Defaults to True. - **disable_webgl**: (bool) - Whether to disable WebGL to block fingerprinting. Defaults to True. - **browser_connection_timeout**: (float) - Timeout in seconds for establishing a browser connection. - **browser_connection_max_tries**: (int) - Maximum number of attempts to connect to the browser. - **host**: (str) - The host to connect to for an existing debuggable Chrome instance. - **port**: (int) - The port to connect to for an existing debuggable Chrome instance. ### Request Example ```python config = Config( headless=True, sandbox=False, # required when running as root (Linux) lang="de-DE", user_agent="CustomAgent/1.0", disable_webrtc=True, # prevent WebRTC IP leaks (default True) disable_webgl=True, # block WebGL fingerprinting browser_connection_timeout=0.5, browser_connection_max_tries=20, ) # Add arbitrary Chromium flags config.add_argument("--disable-notifications") config.add_argument("--blink-settings=imagesEnabled=false") # Load an unpacked extension config.add_extension("/path/to/my-extension/") # Connect to an already-running debuggable Chrome config.host = "127.0.0.1" config.port = 9222 # existing --remote-debugging-port browser = await zd.Browser.create(config) ``` ``` -------------------------------- ### Enable Runtime Domain with CDP Source: https://github.com/cdpdriver/zendriver/blob/main/docs/tutorials/cdp.md Send a CDP command to enable the runtime domain. This is a foundational step for interacting with browser runtime functionalities via CDP. ```python from zendriver.script import Script def main(script: Script): # Enable the runtime domain script.cdp.send("Runtime.enable") print("Runtime domain enabled") ``` -------------------------------- ### Download Files with Tab.download_file() Source: https://context7.com/cdpdriver/zendriver/llms.txt Triggers a file download by injecting JavaScript. The download is saved to a specified directory or a default ./downloads/ folder. Ensure the download path is set before initiating downloads. ```python import asyncio import zendriver as zd async def main(): browser = await zd.start() tab = await browser.get("https://example.com") # Set download directory first await tab.set_download_path("/tmp/downloads") # Download a specific file await tab.download_file( "https://example.com/report.pdf", filename="my_report.pdf" ) # Download all linked files from a page urls = await tab.get_all_urls() pdf_urls = [u for u in urls if u.endswith(".pdf")] for url in pdf_urls: await tab.download_file(url) await asyncio.sleep(3) # Wait for downloads to complete await browser.stop() asyncio.run(main()) ``` -------------------------------- ### Build Key Event Sequences with KeyEvents.from_mixed_input() Source: https://context7.com/cdpdriver/zendriver/llms.txt Use this class method to construct CDP-ready key event sequences from a mix of text, SpecialKeys, and (key, modifier) tuples. The output is suitable for Element.send_keys(). ```python import asyncio import zendriver as zd from zendriver import KeyEvents, KeyModifiers, KeyPressEvent, SpecialKeys async def main(): browser = await zd.start() tab = await browser.get("https://example.com/editor") editor = await tab.select("div[contenteditable='true']") # Type, select-all, bold via Ctrl+B events = KeyEvents.from_mixed_input([ "Hello World", ("a", KeyModifiers.Ctrl), # Ctrl+A (select all) ("b", KeyModifiers.Ctrl), # Ctrl+B (bold) SpecialKeys.ARROW_RIGHT, # deselect SpecialKeys.ENTER, "New line here", ], ascii_keypress=KeyPressEvent.DOWN_AND_UP) await editor.send_keys(events) await browser.stop() asyncio.run(main()) ``` -------------------------------- ### Execute Raw CDP Commands with `Tab.send()` Source: https://context7.com/cdpdriver/zendriver/llms.txt Illustrates sending raw CDP commands directly using typed `cdp.*` module objects for full access to CDP domains. This is the lowest-level API. ```python import asyncio import zendriver as zd from zendriver import cdp async def main(): browser = await zd.start() tab = await browser.get("https://example.com") # Enable DOM domain await tab.send(cdp.dom.enable()) # Get full DOM tree doc = await tab.send(cdp.dom.get_document(depth=-1, pierce=True)) # Capture screenshot with custom clip clip = cdp.page.Viewport(x=0, y=0, width=400, height=300, scale=1) data = await tab.send(cdp.page.capture_screenshot(format_="png", clip=clip)) # Emulate device metrics (mobile) await tab.send(cdp.emulation.set_device_metrics_override( width=375, height=812, device_scale_factor=3, mobile=True, )) # Navigate with CDP directly await tab.send(cdp.page.navigate("https://example.org")) await browser.stop() asyncio.run(main()) ``` -------------------------------- ### Drag and Drop Elements with `Element.mouse_drag()` Source: https://context7.com/cdpdriver/zendriver/llms.txt Demonstrates how to drag an element to a target element or relative coordinates. Use the `steps` parameter for smoother motion. ```python import asyncio import zendriver as zd async def main(): browser = await zd.start() tab = await browser.get("https://example.com/drag-demo") source = await tab.select("#draggable") target = await tab.select("#droptarget") # Drag to another element await source.mouse_drag(target, steps=20) # Drag by relative offset (right 200px, down 100px) await source.mouse_drag((200, 100), relative=True, steps=30) await browser.stop() asyncio.run(main()) ``` -------------------------------- ### Download Grocery List JavaScript Function Source: https://github.com/cdpdriver/zendriver/blob/main/tests/sample_data/groceries.html Use this function to create a text file of groceries and trigger a download. Ensure the DOM is ready before calling this function. ```javascript function downloadGroceryList() { const groceries = [ "Apples (42)", "Bananas", "Carrots", "Donuts", "Eggs", "French Fries", "Grapes" ]; const blob = new Blob([groceries.join('\n')], { type: 'text/plain' }); const a = document.createElement('a'); a.href = URL.createObjectURL(blob); a.download = 'grocery_list.txt'; document.body.appendChild(a); a.click(); document.body.removeChild(a); } ``` -------------------------------- ### Listen to Console Messages via CDP Source: https://github.com/cdpdriver/zendriver/blob/main/docs/tutorials/cdp.md Listen for console messages using CDP and print them to the console. This requires enabling the runtime domain first. ```python from zendriver.script import Script def main(script: Script): # Enable the runtime domain script.cdp.send("Runtime.enable") print("Runtime domain enabled") # Subscribe to console messages script.cdp.on("Runtime.consoleAPICalled", lambda msg: print(f"Console message: {msg['args'][0]['value']}")) print("Listening for console messages...") # Keep the script running to listen for events script.wait_forever() ``` -------------------------------- ### Run Linting and Type Checking Source: https://github.com/cdpdriver/zendriver/blob/main/CONTRIBUTING.md Execute the provided script to ensure code formatting and type correctness using ruff and mypy. This should be run before submitting changes. ```bash scripts/lint.sh ``` -------------------------------- ### Tab.expect_download() Source: https://context7.com/cdpdriver/zendriver/llms.txt An async context manager that intercepts the next file download before it begins, providing access to the download URL and suggested filename. The download is blocked until explicitly handled. ```APIDOC ## `Tab.expect_download()` — Intercept file downloads An async context manager that intercepts the next file download before it begins, giving access to the download URL and suggested filename. The download is blocked until you explicitly handle it. ### Parameters #### Path Parameters - **timeout** (float) - Optional - The maximum time in seconds to wait for the download event. ### Request Example ```python import asyncio import base64 import zendriver as zd async def main(): browser = await zd.start() tab = await browser.get("https://translate.yandex.com/en/ocr") # Upload a file file_input = await tab.select('input[type="file"]') await file_input.send_file("/tmp/image.png") await asyncio.sleep(3) # Intercept the download async with tab.expect_download() as dl_ex: download_btn = await tab.select("#downloadButton") await download_btn.mouse_click() download = await dl_ex.value print(download.suggested_filename) # Write the file manually from base64 data URL data = base64.b64decode(download.url.split(",", 1)[-1]) with open(download.suggested_filename, "wb") as f: f.write(data) await browser.stop() asyncio.run(main()) ``` ``` -------------------------------- ### Navigate to a URL with Browser.get() Source: https://context7.com/cdpdriver/zendriver/llms.txt The `Browser.get()` method navigates the current tab or opens a new one to a specified URL. It waits for the `TargetInfoChanged` event, ensuring the DOM is ready for interaction upon return. Supports opening URLs in new tabs or windows. ```python import asyncio import zendriver as zd async def main(): browser = await zd.start() # Navigate existing tab tab = await browser.get("https://example.com") # Open in a new tab tab2 = await browser.get("https://github.com", new_tab=True) # Open in a new window tab3 = await browser.get("https://google.com", new_window=True) print(browser.tabs) # [, , ] print(browser.main_tab) # first tab await browser.stop() asyncio.run(main()) ``` -------------------------------- ### Zendriver Configuration using Config Object Source: https://github.com/cdpdriver/zendriver/blob/main/docs/quickstart.md Configure Zendriver settings using a Config object for headless mode, user data directory, browser executable path, arguments, and language. This approach allows for modular configuration. ```python import zendriver as zd config = zd.Config() config.headless = False config.user_data_dir="/path/to/existing/profile", # by specifying it, it won't be automatically cleaned up when finished config.browser_executable_path="/path/to/some/other/browser", config.browser_args=['--some-browser-arg=true', '--some-other-option'], config.lang="en-US" # this could set iso-language-code in navigator, not recommended to change ``` -------------------------------- ### Simulate Mouse Input with Tab.mouse_click() / Tab.mouse_move() Source: https://context7.com/cdpdriver/zendriver/llms.txt Dispatches native CDP mouse events at exact screen coordinates, bypassing JavaScript listeners. The flash parameter aids debugging by showing a red dot at the click position. ```python import asyncio import zendriver as zd async def main(): browser = await zd.start() tab = await browser.get("https://example.com") # Click at absolute screen coordinates await tab.mouse_click(x=640, y=400, button="left", flash=True) # Right-click await tab.mouse_click(x=640, y=400, button="right") # Move mouse to a position (triggers hover effects) await tab.mouse_move(x=200, y=300, steps=10) await browser.stop() asyncio.run(main()) ``` -------------------------------- ### Browser.get() Source: https://context7.com/cdpdriver/zendriver/llms.txt Navigates the current or a new tab to a specified URL. This method waits for the `TargetInfoChanged` event, ensuring the DOM is ready for interaction upon return. It can open the URL in the existing tab, a new tab, or a new window. ```APIDOC ## Browser.get() — Navigate to a URL Navigates the first open tab to a URL, or opens a new tab/window. Waits for the DOM `TargetInfoChanged` event before returning, making it safe to immediately interact with the page. ### Method GET ### Endpoint /browser/{id}/navigate ### Parameters #### Path Parameters - **id** (string) - Required - The ID of the browser instance. #### Query Parameters - **url** (string) - Required - The URL to navigate to. - **new_tab** (boolean) - Optional - If true, opens the URL in a new tab. - **new_window** (boolean) - Optional - If true, opens the URL in a new window. ### Request Example ```python import asyncio import zendriver as zd async def main(): browser = await zd.start() # Navigate existing tab tab = await browser.get("https://example.com") # Open in a new tab tab2 = await browser.get("https://github.com", new_tab=True) # Open in a new window tab3 = await browser.get("https://google.com", new_window=True) print(browser.tabs) # [, , ] print(browser.main_tab) # first tab await browser.stop() asyncio.run(main()) ``` ### Response #### Success Response (200) - **Tab** (object) - A Tab object representing the navigated page. ``` -------------------------------- ### Waiting for Cards to Load Source: https://github.com/cdpdriver/zendriver/blob/main/docs/tutorials/infinite-scrolling.md This version introduces waiting for the cards to appear before attempting to find them, improving the reliability of element detection. ```python # Import necessary libraries from cdpdriver import CDPDRIVER from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC # Initialize CDPDRIVER driver = CDPDRIVER() # Navigate to the target page driver.get("https://cdpdriver.github.io/examples/scrollable-cards.html") # Wait for at least one card to be present wait = WebDriverWait(driver, 10) wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, ".card"))) # Find all card elements cards = driver.find_elements_by_css_selector(".card") print(f"Found {len(cards)} cards after waiting.") # Close the browser driver.quit() ``` -------------------------------- ### Tab.expect_request() / Tab.expect_response() Source: https://context7.com/cdpdriver/zendriver/llms.txt Async context managers that register handlers for network events, matching by URL regex pattern. Allows capturing matched events and response bodies. ```APIDOC ## `Tab.expect_request()` / `Tab.expect_response()` — Intercept network events Async context managers that register handlers for network `RequestWillBeSent` and `ResponseReceived` CDP events, matching by URL regex pattern. Use `await expectation.value` to get the matched event, and `await expectation.response_body` to retrieve the response body. ### Parameters #### Path Parameters - **url_pattern** (string or re.Pattern) - Required - A URL pattern or regex to match requests/responses. - **timeout** (float) - Optional - The maximum time in seconds to wait for the event. ### Request Example ```python import asyncio import re import zendriver as zd async def main(): browser = await zd.start() tab = await browser.get("https://httpbin.org") # Capture an API response matching a URL pattern async with tab.expect_response(re.compile(r".*httpbin.org/get.*?")) as resp_ex: await tab.get("https://httpbin.org/get") response = await resp_ex.response body, is_base64 = await resp_ex.response_body print(response.status) # 200 print(body[:200]) # {"args": {}, "headers": {...}, ...} # Capture a request before it is sent async with tab.expect_request("https://httpbin.org/post") as req_ex: await tab.evaluate( "fetch('https://httpbin.org/post', {method:'POST', body:'hello'})" ) request = await req_ex.request print(request.method, request.url) # POST https://httpbin.org/post await browser.stop() asyncio.run(main()) ``` ``` -------------------------------- ### Wait for Page Load State with Tab.wait_for_ready_state() Source: https://context7.com/cdpdriver/zendriver/llms.txt Polls document.readyState until it matches the target state. Raises asyncio.TimeoutError if the state is not reached within the specified timeout. ```python import asyncio import zendriver as zd async def main(): browser = await zd.start() tab = await browser.get("https://example.com") # Wait for full load (all resources) await tab.wait_for_ready_state("complete", timeout=15) # Wait for interactive (DOM ready, resources may still load) await tab.wait_for_ready_state("interactive", timeout=10) content = await tab.get_content() print(len(content), "chars loaded") await browser.stop() asyncio.run(main()) ``` -------------------------------- ### Grant All Browser Permissions Source: https://context7.com/cdpdriver/zendriver/llms.txt Call `browser.grant_all_permissions()` to preemptively grant all necessary permissions, preventing interruptions from prompts during automation. ```python import asyncio import zendriver as zd async def main(): browser = await zd.start() await browser.grant_all_permissions() tab = await browser.get("https://maps.google.com") # No geolocation prompt will appear await browser.stop() asyncio.run(main()) ``` -------------------------------- ### Upload Files with Element.send_file() Source: https://context7.com/cdpdriver/zendriver/llms.txt Uploads one or more files to an `` element using CDP `DOM.setFileInputFiles`. This bypasses the OS file picker. ```python import asyncio import zendriver as zd async def main(): browser = await zd.start() tab = await browser.get("https://imgur.com/upload") # Single file upload file_input = await tab.select("input[type=file]") await file_input.send_file("/home/user/photo.jpg") # Multiple files (input must have `multiple` attribute) await file_input.send_file( "/tmp/doc1.pdf", "/tmp/doc2.pdf", "/tmp/image.png", ) await browser.stop() asyncio.run(main()) ``` -------------------------------- ### Intercept File Downloads with Tab.expect_download() Source: https://context7.com/cdpdriver/zendriver/llms.txt An async context manager that intercepts the next file download before it begins, giving access to the download URL and suggested filename. The download is blocked until explicitly handled. ```python import asyncio import base64 import zendriver as zd async def main(): browser = await zd.start() tab = await browser.get("https://translate.yandex.com/en/ocr") # Upload a file file_input = await tab.select('input[type="file"]') await file_input.send_file("/tmp/image.png") await asyncio.sleep(3) # Intercept the download async with tab.expect_download() as dl_ex: download_btn = await tab.select("#downloadButton") await download_btn.mouse_click() download = await dl_ex.value print(download.suggested_filename) # Write the file manually from base64 data URL data = base64.b64decode(download.url.split(",", 1)[-1]) with open(download.suggested_filename, "wb") as f: f.write(data) await browser.stop() asyncio.run(main()) ``` -------------------------------- ### Tab.get_local_storage() / Tab.set_local_storage() Source: https://context7.com/cdpdriver/zendriver/llms.txt Provides access to the browser's `localStorage` for the current page origin using the CDP's `DOMStorage` domain. `get_local_storage()` reads the current items, and `set_local_storage()` writes new items. ```APIDOC ## `Tab.get_local_storage()` / `Tab.set_local_storage()` — localStorage access Reads or writes the browser's `localStorage` for the current page origin via CDP's `DOMStorage` domain. ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body (for `set_local_storage`) - **items** (dict) - Required - A dictionary where keys are localStorage item names and values are their string representations. ### Request Example (`get_local_storage`) ```python items = await tab.get_local_storage() print(items) # {"key": "value", ...} ``` ### Request Example (`set_local_storage`) ```python await tab.set_local_storage({ "auth_token": "eyJhbGci...", "user_pref": '{"theme": "dark"}', }) ``` ### Response (`get_local_storage`) #### Success Response (200) - **items** (dict) - A dictionary containing key-value pairs from localStorage. #### Response Example (`get_local_storage`) ```json { "key": "value" } ``` ``` -------------------------------- ### Element Screenshots with Element.save_screenshot() / Element.screenshot_b64() Source: https://context7.com/cdpdriver/zendriver/llms.txt Captures a screenshot of an element's bounding box. Raises `RuntimeError` if the element is hidden or has no size. `save_screenshot` saves to a file, while `screenshot_b64` returns base64 encoded data. ```python import asyncio import zendriver as zd async def main(): browser = await zd.start() tab = await browser.get("https://example.com") # Screenshot just the heading heading = await tab.select("h1") path = await heading.save_screenshot("heading.png", format="png", scale=2) print(f"Element screenshot saved to: {path}") # Base64 for direct use b64 = await heading.screenshot_b64(format="jpeg", scale=1) print(b64[:60] + "...") await browser.stop() asyncio.run(main()) ``` -------------------------------- ### Run Tests Source: https://github.com/cdpdriver/zendriver/blob/main/CONTRIBUTING.md Execute all project tests using pytest. Ensure all tests pass before submitting a pull request. ```bash uv run pytest ``` -------------------------------- ### Element.save_screenshot() / Element.screenshot_b64() Source: https://context7.com/cdpdriver/zendriver/llms.txt Captures a screenshot of the element's bounding box, either saving to a file or returning as a base64 string. ```APIDOC ## Element.save_screenshot() / Element.screenshot_b64() ### Description Captures a screenshot of only the bounding box of the specific element. Raises `RuntimeError` if the element is hidden or has no size. ### Method `await element.save_screenshot(path, format='png', scale=1)` `await element.screenshot_b64(format='png', scale=1)` ### Parameters - **path**: `str`, Required for `save_screenshot` - The file path to save the screenshot. - **format**: `str`, Optional - The image format ('png' or 'jpeg'). Defaults to 'png'. - **scale**: `int`, Optional - The scale factor for the screenshot. Defaults to 1. ### Request Example ```python # Save screenshot to file path = await heading.save_screenshot("heading.png", format="png", scale=2) # Get base64 encoded screenshot b64 = await heading.screenshot_b64(format="jpeg", scale=1) ``` ``` -------------------------------- ### Fetch User Data with JavaScript Source: https://github.com/cdpdriver/zendriver/blob/main/tests/sample_data/profile.html Use this JavaScript code to fetch data from a JSON endpoint when the window loads. It updates an HTML element with the fetched data or an error message. ```javascript window.onload = function () { fetch('https://cdpdriver.github.io/examples/user-data.json') .then(response => response.json()) .then(data => { document.getElementById('result').textContent = JSON.stringify(data, null, 2); }) .catch(error => { document.getElementById('result').textContent = 'Error: ' + error; }); }; ```