Skip to main content

Lightweight Chrome Debug Protocol (CDP) client for python

Project description

fastcdp

fastcdp provides an async Python client for the Chrome DevTools Protocol (CDP) over WebSocket. It auto-discovers Chrome’s debug port, loads the full protocol schema from bundled JSON files, and exposes every CDP domain as a Python attribute with auto-generated signatures and docstrings — e.g. await cdp.page.navigate(url=...).

It includes a Page class for tab-scoped operations, event subscription via cdp.on()/cdp.wait_event(), navigation helpers (goto, wait_for_selector, wait_for), screenshot capture, and accessibility tree access. A cdp_search utility lets you search CDP commands by name or description. For use inside safepyrun sandboxes, cdp_yolo() registers all CDP classes.

Installation

Install latest from pypi

$ pip install fastcdp

How to use

from fastcdp import *

Chrome 146+ has built-in remote debugging support. Navigate to chrome://inspect/#remote-debugging and enable “Allow remote debugging for this browser instance”:

image.png

The CDP class

Connect to Chrome (which will pop up a permissions window):

cdp = await CDP.connect()

Every CDP domain is available as an attribute with auto-generated signatures. You can search for commands with cdp_search:

cdp_search('screenshot')
"Emulation.setVisibleSize: Resizes the frame/viewport of the page. Note that this does not affect the frame's container\n(e.g. browser window). Can \nHeadlessExperimental.beginFrame: Sends a BeginFrame to the target and returns when the frame was completed. Optionally captures a\nscreenshot from the res\n  evt Overlay.screenshotRequested: Fired when user asks to capture screenshot of some area on the page.\nPage.captureScreenshot: Capture page screenshot."

List open pages and attach to one:

ps = await cdp.pages
pg = ps[0]
pg['title']
'8. Database Transactions — PlanetScale'
tid = pg['targetId']
sid = await cdp.attach(tid)
await cdp.eval('document.title', sid)
'8. Database Transactions — PlanetScale'

The Page class wraps a tab with its own session, so you don’t need to pass sid everywhere:

page = await cdp.new_page()
await page.goto('https://httpbin.org/forms/post')

You can wait_for any js expression to be truthy, and have it returned:

await page.wait_for('document.title')
'6. httpbin.org/forms/post'

Take a screenshot of the page:

img = await page.screenshot()

Clean up when done:

await page.close()
await cdp.close()

See CDP docs for full details.

Page.new and Filling forms

Instead of CDP.connect, you can call Page.new with no params to automatically create a CDP object and attach it to a new page:

page = await Page.new()
await page.goto('https://httpbin.org/forms/post')

For finding elements to interact with, use ax_tree:

root = await page.ax_tree()
print(str(root)[:300])
- **RootWebArea** "6. httpbin.org/forms/post" `focusable=True` `focused=True` `url=https://httpbin.org/forms/post` [#2]
  - **LabelText** "" [#24]
    - **StaticText** "Customer name: " [#64]
      - **InlineTextBox** "Customer name: "
    - **textbox** "Customer name: " `focusable=True` `editable=p

find and find_id are used to identify elements in the tree:

nmid = root.find_id('textbox', 'Customer name')
nmid
4

You can use regular CDP methods, or one of the provided shortcuts:

await page.fill_text(nmid, 'Jeremy Howard')
await page.click(root.find_id('radio', 'Large'))
await page.js_node_run('this.value = "18:30"', root.find_id('InputTime', 'delivery time'))
{'type': 'undefined'}

You can use click to click a button, or click_and_wait to wait for the next page to load:

await page.click_and_wait(root.find_id('button', 'Submit order'))

When using page.New(), close() also shuts down the CDP websocket.

await page.close()

To allow LLMs like solveit with safepyrun to access fastcdp, use:

cdp_yolo()

Then open a controlled page for it:

page = await Page.new()

Then use a prompt such as:

Try using pyrun to go to <url> using the existing page, fill it out, read it to check it’s filled correctly, then submit it, and see what you get back. Don’t use find_id - you can get all the ids at once with ax_tree (don’t truncate the result of it). Don’t add extra waits etc - fastcdp handles it automatically. IDs can change so be sure to use the ax_tree IDs you read.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fastcdp-0.0.4.tar.gz (180.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fastcdp-0.0.4-py3-none-any.whl (183.6 kB view details)

Uploaded Python 3

File details

Details for the file fastcdp-0.0.4.tar.gz.

File metadata

  • Download URL: fastcdp-0.0.4.tar.gz
  • Upload date:
  • Size: 180.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.0

File hashes

Hashes for fastcdp-0.0.4.tar.gz
Algorithm Hash digest
SHA256 7f6652301749514ecb571b7ceb604d5721ce6cab054b8b9d58341e0bb35a67ca
MD5 77713829c22a1939a15f90d154088554
BLAKE2b-256 c21629b9716b0adb13f4fb2039a8401119b29b5eed884c427694990d84b2b13d

See more details on using hashes here.

File details

Details for the file fastcdp-0.0.4-py3-none-any.whl.

File metadata

  • Download URL: fastcdp-0.0.4-py3-none-any.whl
  • Upload date:
  • Size: 183.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.0

File hashes

Hashes for fastcdp-0.0.4-py3-none-any.whl
Algorithm Hash digest
SHA256 40507f18c00c94d3601866763778e7fc432ec3ff0efd505fa8a553b880374fd2
MD5 9982833590543b08e364ecf551f70f78
BLAKE2b-256 c9dbdc789156eed371429129fdfc488cf4d0ee0b1d80976c56ea0da1588d8dba

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page