cdp_app
def cdp_app(
url, port:int=9223, user_data_dir:NoneType=None, wait:int=15
):Open url as an app window – no tabs, no address bar – in the persistent debug Chrome.
Attach to a running Chrome with cdp_connect(). pg.snapshot() gives an agent a compact a11y map; fill_form / act drive it. Network capture + replay for hidden APIs.
Open url as an app window – no tabs, no address bar – in the persistent debug Chrome.
Websocket debugger URL of the debug Chrome on port, starting one (headless by default) if needed. For scrapling’s cdp_url=.
Connect to a debug Chrome on port; if none is running, set one up on a persistent profile and connect.
Start a persistent debug Chrome on port with its own profile, ready for CDP.remote
Evaluate expr in the page and return its decoded value.
Upgrades fastcdp’s eval in three ways every caller wants: promises are awaited, objects and arrays come back as Python values instead of None, and a JS exception is raised as JSError rather than silently read as an empty result.
JavaScript raised while evaluating an expression in the page.
- **RootWebArea** "New Tab" `focusable=True` `url=chrome://new-tab-page/` [#1]
- **Iframe** "" [#44]
- **combobox** "Search Google or type a URL" `live=polite` `relevant=additions text` `focusable=True` `editable=plaintext` `settable=True` `hasPopup=listbox` [#24]
- **button** "Search by voice
- **RootWebArea** "VedicReader" `focusable=True` `focused=True` `url=https://vedicreader.com/` [#2]
- **navigation** "" [#128]
- **link** "Vr." `focusable=True` `url=https://vedicreader.com/` [#129]
- **heading** "Vr." `level=4` [#130]
- **StaticText** "Vr." [#262]
- **
cdp_install / keep-alive launch a persistent profile. Cookies survive restarts.
# LIST — is a debug Chrome up, and what's open in it?
import httpx
port = 9223
print('running on 9223?', _debug_running(port))
ver = httpx.get(f'http://127.0.0.1:{port}/json/version').json()
print('browser:', ver['Browser'], '| ws:', ver['webSocketDebuggerUrl'])
for t in httpx.get(f'http://127.0.0.1:{port}/json/list').json(): # open tabs/pages
print(' ', t['type'], '|', t['title'][:40], '|', t['url'][:50])
print('live debug ports:', [p for p in (9222, 9223, 9224) if _debug_running(p)])running on 9223? True
browser: Chrome/150.0.7871.129 | ws: ws://127.0.0.1:9223/devtools/browser/bb4a47a3-b032-4afd-b398-83f1de66a3ab
page | Gayathri Dhyaanam | https://vedicreader.com/
page | New Tab | chrome://newtab/
iframe | chrome-untrusted://new-tab-page/one-goog | chrome-untrusted://new-tab-page/one-google-bar?par
browser_ui | Omnibox Popup | chrome://omnibox-popup.top-chrome/
browser_ui | Omnibox Popup | chrome://omnibox-popup.top-chrome/omnibox_popup_ai
service_worker | Service Worker chrome-extension://ilaikd | chrome-extension://ilaikdjkclophmmhodhgfmnimfeohkg
service_worker | Service Worker chrome-extension://hbicfl | chrome-extension://hbicflpnhfmdndpibdegbnkkpngjbhf
service_worker | Service Worker chrome-extension://epnhoe | chrome-extension://epnhoepnmfjdbjjfanpjklemanhkjgi
live debug ports: [9223]
# CLOSE a single tab, QUIT the whole browser, then RELAUNCH it HEADED for interactive login
import httpx, time
port = 9223
tabs = httpx.get(f'http://127.0.0.1:{port}/json/list').json()
if tabs: httpx.get(f"http://127.0.0.1:{port}/json/close/{tabs[0]['id']}") # close one tab by target id
cdp = syncy(cdp_connect(port=port))
try: syncy(cdp.quit()) # quit browser+connection; raises ConnectionClosedOK as the socket drops
except Exception: pass
time.sleep(1.5)
assert not _debug_running(port), 'browser should be down after quit()'
syncy(cdp_setup(port, headless=False)) # relaunch HEADED so you can log in by hand
assert _debug_running(port)
print('headed Chrome ready on', port, '— log in, then reuse it via fetch(url, session=True)')headed Chrome ready on 9223 — log in, then reuse it via fetch(url, session=True)
cdp_app opens a headed app window on the persistent profile.
# cdp_app's flags: an app window, headed, on the persistent profile. No browser is launched here.
flags = _chrome_flags(9223, _profile_dir(), False, ['--app=http://alpha.localhost:5001/'])
assert '--app=http://alpha.localhost:5001/' in flags
assert '--headless=new' not in flags # an app window you cannot see is useless
assert f'--user-data-dir={_profile_dir()}' in flags # same profile as cdp_setup, so logins carry
assert str(_profile_dir()).endswith('cdp-chrome')
assert _profile_dir('~/x') == Path.home()/'x' # user_data_dir wins, and ~ is expanded# cdp_app end to end against a stubbed browser: reuse a running Chrome, report its target.
# The stubs rebind this notebook's own names, because that is what `cdp_app` resolves at call
# time -- patching `fossick.cdp` would leave the definitions in these cells untouched.
import httpx, subprocess as _sp
_saved = (_debug_ready, _sp.Popen, httpx.get)
launched = []
class _Targets:
def json(self): return [{'id': 'target-1', 'url': 'http://alpha.localhost:5001/'}]
try:
_debug_ready = lambda port, host='127.0.0.1': True # a debug Chrome is already up
_sp.Popen = lambda args, **kw: launched.append(args)
httpx.get = lambda url, **kw: _Targets()
r = cdp_app('http://alpha.localhost:5001/', wait=1)
finally:
_debug_ready, _sp.Popen, httpx.get = _saved
assert r['ok'] and r['reused'] is True # reused, so no second resident browser
assert r['target'] == 'target-1' # and the window was found by its url
assert r['url'] == 'http://alpha.localhost:5001/' and r['port'] == 9223
assert '--app=http://alpha.localhost:5001/' in launched[0]
assert f'--user-data-dir={_profile_dir()}' in launched[0]
print('cdp_app:', {k: r[k] for k in ('reused', 'target')})cdp_app: {'reused': True, 'target': 'target-1'}
# Open two app windows on one browser and confirm the second reused the first's process.
a = cdp_app('https://example.com/')
b = cdp_app('https://example.org/')
assert a['ok'] and b['ok']
assert b['reused'], 'the second window should reuse the browser the first one started'
assert a['profile'] == b['profile']
print('windows:', a['target'], b['target'], '| reused:', a['reused'], b['reused'])Outgoing requests matching pattern. Navigates if url given, else passive.
Export cookies from the running debug Chrome. Returns Playwright-format list (for scrapling cookies=), or {name: value} if as_dict.
Live page as clean markdown via fossick’s to_md (optionally narrowed to CSS sel)
Fill a form by field label/name: {label: value}. Native