Metadata-Version: 2.4
Name: fastcdp
Version: 0.0.15
Summary: Lightweight Chrome Debug Protocol (CDP) client for python
Author-email: Jeremy Howard <github@jhoward.fastmail.fm>
License: Apache-2.0
Project-URL: Repository, https://github.com/AnswerDotAI/fastcdp
Project-URL: Documentation, https://AnswerDotAI.github.io/fastcdp/
Keywords: nbdev
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: websockets
Requires-Dist: httpx
Requires-Dist: fastcore>=2.2.23
Provides-Extra: dev
Requires-Dist: pyskills>=0.0.30; extra == "dev"
Dynamic: license-file

# fastcdp


<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->

`fastcdp` is an async Python client for the [Chrome DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/) (CDP) over WebSocket. Use it to automate your everyday Chrome browser or a separate Chrome instance. It can launch Chrome or connect to a running browser.

Every CDP domain is available as a Python attribute, such as `await cdp.page.navigate(url=...)`. fastcdp loads the full protocol schema from bundled JSON files to generate signatures and docstrings. It discovers Chrome’s debug port automatically.

The [`Page`](https://AnswerDotAI.github.io/fastcdp/core.html#page) class provides tab-scoped operations for navigation, content waits, screenshots, and accessibility tree access. The examples below use it to inspect and fill a form.

## Installation

Install latest from [pypi](https://pypi.org/project/fastcdp/)

``` sh
$ pip install fastcdp
```

## How to use

``` python
from fastcdp import *
```

Choose one of five connection methods. Read `doc(fastcdp.skill)` for browser-selection and ownership guidance, then the chosen method’s full docs:

- `cdp = await CDP.launch()` starts or reuses Chrome with a separate automation profile. The default profile persists between runs.
- `cdp = await CDP.connect()` attaches to an everyday Chrome with remote debugging enabled and the user’s approval.
- `cdp = await CDP.remote()` attaches to a dedicated debug browser. `fastcdp-setup` creates a launcher for this configuration.
- `cdp = await ExtCDP.listen()` waits for the [fastcdp-chrome](https://github.com/AnswerDotAI/fastcdp-chrome) extension in the requested browser.
- `async with CDP.testing(headless=True) as cdp:` owns a disposable Chrome for Testing and temporary profile. Install it once with `fastcdp-setup --install stable`; the context closes the browser and removes the profile when finished. It leaves your installed Chrome and CDP Chrome setup untouched.

This walkthrough uses `connect`:

In Chrome 146 or later, open `chrome://inspect/#remote-debugging` and enable “Allow remote debugging for this browser instance”:

![image.png](index_files/figure-commonmark/65d1f5d3-1-5d9f96ff-4344-43ee-bb5d-00d465cf1f79.png)

### The CDP class

Connect to Chrome and approve its permission prompt:

``` python
cdp = await CDP.connect()
```

Use `cdp.on()` to subscribe to events or `cdp.wait_event()` to wait for an event. To find commands by name or description, use [`cdp_search`](https://AnswerDotAI.github.io/fastcdp/core.html#cdp_search):

``` python
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:

``` python
ps = await cdp.pages
pg = ps[0]
pg['title']
```

    '8. Database Transactions — PlanetScale'

``` python
tid = pg['targetId']
sid = await cdp.attach(tid)
await cdp.eval('document.title', sid)
```

    '8. Database Transactions — PlanetScale'

[`Page`](https://AnswerDotAI.github.io/fastcdp/core.html#page) holds a tab’s session. Its helpers bind `sid`. Read `doc(page)` to discover those helpers and protocol domains, then `doc(page.goto)` or `doc(page.DOM.focus)` for a selected operation. Connection-wide operations such as creating tabs remain on `page.cdp`:

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

Choose how `goto` waits for navigation:

- By default, it waits for the document’s `load` event.
- `wait='idle'` also waits for initial network activity to settle.
- `wait=None` skips the navigation wait. Use a subsequent content wait to check application-specific readiness.

`wait_for_selector` waits for an element. `wait_for` waits for a JavaScript expression to become truthy and returns its value:

``` python
await page.wait_for('document.title')
```

    '6. httpbin.org/forms/post'

Take a screenshot of the page:

``` python
img = await page.screenshot()
```

Clean up when done:

``` python
await page.close()
await cdp.close()
```

See [`CDP`](https://AnswerDotAI.github.io/fastcdp/core.html#cdp) docs for full details.

## Page.new and filling forms

Call [`Page.new()`](https://AnswerDotAI.github.io/fastcdp/core.html#page.new) without arguments to create a CDP object and attach it to a new page:

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

Use `ax_tree` to find elements through the accessibility tree. Pass `frame_id=` to read a child frame directly:

``` python
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

Use `find` and `find_id` to locate elements in the tree:

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

    4

`page.attrs` reads an element’s HTML attributes by node id or CSS selector. For example, `await page.attrs(nmid)` and `await page.attrs('[name=custname]')` each return a dictionary.

`await page.sel_attrs('input', 'name', 'type')` returns one dictionary per matching element. Missing requested attributes have the value `None`. Omit the attribute names to read all attributes.

Interact with elements using CDP methods or these shortcuts:

``` python
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'}

Choose the input method according to the interaction you need:

- `click` moves the real mouse before pressing and releasing.
- `tap` sends a trusted Chrome tap gesture without moving the mouse. Use it when mouse movement is unreliable or hover is undesirable.
- `dom_click` calls the element’s JavaScript activation. It does not produce trusted input.

`click_and_wait` clicks and waits for a top-frame navigation. For another activation method, use `expect_navigation` around that operation. For in-place UI updates, activate the element normally and wait for the resulting content.

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

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

``` python
await page.close()
```

For an LLM using fastcdp through [safepyrun](https://github.com/AnswerDotAI/safepyrun), such as in Solveit, register all CDP classes with:

``` python
cdp_yolo()
```

Then open a controlled page for it:

``` python
page = await Page.new()
```

Then use a prompt such as:

> Try using python 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.
