solvecdp

Lightweight Chrome Debug Protocol (CDP) client for solveit

solvecdp is fastcdp for solveit: the same async Python client for the Chrome DevTools Protocol, but driving the user’s own browser from a solveit kernel. Every CDP domain is a Python attribute with auto-generated signatures and docstrings, plus event subscription, navigation and form helpers, accessibility tree access, and console/network/dialog debugging buffers. Since the kernel runs on a remote server, frames are relayed through solveit’s /wsx websocket channel to the solveit-chrome extension, which executes them with chrome.debugger.

Installation

You must install the solveit-chrome extension before using solvecdp.

Solveit already has solvecdp installed, but if you want to install the latest you can get it from pypi:

$ pip install solvecdp

How to use

from solvecdp import *

The JsCDP class

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."

Connect (one connection per browser), then open a tab:

cdp = await JsCDP.connect()
page = await cdp.new_page()

Go to a page:

await page.goto('https://httpbingo.org/forms/post')

Eval js:

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

Or 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()

See JsCDP docs for full details.

Filling forms

page = await cdp.new_page(url='https://httpbingo.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` `url=https://httpbin.org/forms/post` [#14]
  - **LabelText** "" [#20]
    - **StaticText** "Customer name: " [#62]
      - **InlineTextBox** "Customer name: "
    - **textbox** "Customer name: " `focusable=True` `editable=plaintext` `set

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

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

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'));

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'))
await page.close()
await cdp.close()

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

cdp_yolo()

Then use a prompt such as:

Try using python to connect a cdp_ JsCDP object and open a page_ tab with new_page, then goto <url>, 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 - solvecdp handles it automatically. IDs can change so be sure to use the ax_tree IDs you read.