Parsek CDP server — launch, supervise and proxy a browser; server-side feature producers.
Project description
parsek-cdp-server
The server side of parsek-cdp: launching, supervising and proxying a
browser, plus the server-side feature producers that digest raw CDP into
Parsek.* events.
A separate distribution from parsek-cdp (the client); installed via
pip install parsek-cdp[server]. It depends on parsek-cdp and reuses its
shared layers wholesale — the generated cdp protocol, the core primitives
(CDPConnection, Target, DataType) and the parsek contract — adding only
what must live next to the browser.
Документация на русском: README.ru.md.
Running
import asyncio
from parsek_cdp_server import ParsekServer
from parsek_cdp.features import RequestListener
async def main():
server = ParsekServer(idle_timeout=300) # a browser self-closes after 5 min idle
server.register_feature(RequestListener) # make the feature selectable via ?feature=
await server.start("127.0.0.1", 9333)
try:
await asyncio.Event().wait() # keep the server alive
finally:
await server.stop()
asyncio.run(main())
A client connects to this server with
Browser.get_distant_browser("http://127.0.0.1:9333", ...) — the API is
identical to a local browser (see the client README). Every POST /browsers
spins up its own supervised browser; idle_timeout (on the server or in the
request body) closes a browser that sits with no connection.
Where the browser comes from
launcher finds a Chromium-compatible binary on its own. By default it walks
the usual install paths; the PARSEK_CHROMES_PATH env var (directories
separated by os.pathsep, like PATH) overrides the search — each launch picks
a random one of the browsers it finds (a cheap way to spread load and
fingerprints). An explicit path and flags go through LaunchOptions
(executable, headless, extra_args, ...) — either on the server or
per-request in the POST /browsers body.
Modules
| Module | Responsibility |
|---|---|
launcher |
Start Chrome/Chromium, wait for the DevTools endpoint, read the browser-level websocket from /json/version. |
supervisor |
Browser lifecycle: health, crash detection, restart, idle shutdown, and Parsek.browserStateChanged broadcast. |
proxy |
Accept client websockets and bridge each 1:1 to a Chrome target; host feature producers and serve the Parsek.* surface. |
metrics |
Prometheus exposition at /metrics. |
reaper |
A separate subprocess that kills leaked (zombie/orphaned) parsek-launched Chrome processes. |
Connection model
As in the client, every target gets its own websocket (no sessionId
multiplexing). One parsing flow = one browser_context; pages within it each
connect over their own websocket. The proxy bridges a page's client socket to
the corresponding Chrome socket 1:1.
Endpoints
HTTP POST /browsers create a task -> browser_uuid
HTTP GET /metrics Prometheus metrics
ws /cdp/{browser_uuid}/control browser-level pipe + Parsek.browserStateChanged
ws /cdp/{browser_uuid}/page/{target_id} CDP proxy (per-page) + Parsek.*
The control channel is a raw pipe to the browser endpoint plus the
Parsek.browserStateChanged broadcast, so a parser learns when its browser
crashed/restarted instead of hanging; browser-level CDP (creating/disposing
contexts, etc.) passes straight through it.
Features
The server is pure passthrough by default (ParsekServer has no features
argument). Feature producers are added with register_feature(...) and selected
per browser with POST /browsers?feature=<name>. On a page pipe a producer
digests the raw CDP burst into a couple of aggregated Parsek.* events and
suppresses the raw events it consumed; ?raw=1 opts out of suppression.
Metrics (GET /metrics)
| Metric | Type | What |
|---|---|---|
parsek_browsers |
gauge | number of supervised browsers |
parsek_targets{browser,type} |
gauge | targets per browser, by type |
parsek_nested_targets{browser} |
gauge | nested targets (with a parentId) |
parsek_browser_cpu_percent{browser} |
gauge | CPU% of the browser process tree |
parsek_browser_memory_bytes{browser} |
gauge | RSS of the browser process tree |
parsek_cdp_events_total{browser,target,domain} |
counter | CDP events by target and domain |
Targets and CPU/RAM are sampled by a background task (polling /json/list +
psutil), so a scrape only reads cached values and does not block the event
loop. The event counter is labelled by target id — series for dead targets are
pruned on every snapshot.
Zombie reaper
On start the server spawns a separate subprocess (reaper) that
periodically scans for Chrome processes we launched (recognised by the
--user-data-dir=…parsek-cdp-… marker) that became zombies or orphans
(ppid == 1), and kills them along with their subtree. Controlled by
ParsekServer(reap_zombies=..., reap_interval=...); it can also be run by hand:
python -m parsek_cdp_server.reaper --once.
Notes
The Parsek.* contract lives in the client distribution (parsek_cdp.parsek)
and is shared by both sides.
License
Apache-2.0.
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file parsek_cdp_server-0.1.1.tar.gz.
File metadata
- Download URL: parsek_cdp_server-0.1.1.tar.gz
- Upload date:
- Size: 27.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f27e3ce0d267af62ac4a0e55d778e229d455cb2808a49c256af462c3e36292d2
|
|
| MD5 |
c921c629cde8acab45d59040fae8af17
|
|
| BLAKE2b-256 |
0c5f734b09a14021a796fb23a5d7d72c884617c0c5adf5502d558dda3e95d106
|
Provenance
The following attestation bundles were made for parsek_cdp_server-0.1.1.tar.gz:
Publisher:
publish.yml on xa1era/parsek-cdp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
parsek_cdp_server-0.1.1.tar.gz -
Subject digest:
f27e3ce0d267af62ac4a0e55d778e229d455cb2808a49c256af462c3e36292d2 - Sigstore transparency entry: 2044510503
- Sigstore integration time:
-
Permalink:
xa1era/parsek-cdp@f05189f318c3395955d216e586fa4e45a606b28e -
Branch / Tag:
refs/tags/0.1.1 - Owner: https://github.com/xa1era
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f05189f318c3395955d216e586fa4e45a606b28e -
Trigger Event:
release
-
Statement type:
File details
Details for the file parsek_cdp_server-0.1.1-py3-none-any.whl.
File metadata
- Download URL: parsek_cdp_server-0.1.1-py3-none-any.whl
- Upload date:
- Size: 29.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
319364c38003512c1053af8de647156b0b8ac07ef540aa636f1244549c1a10ba
|
|
| MD5 |
2bd96a33a2a2ab5ba96c41cf3c9e8997
|
|
| BLAKE2b-256 |
04e80886ebead3cdec27e7c73f700cd0bdf6da57cbbb581e61f62347b8bcd6a5
|
Provenance
The following attestation bundles were made for parsek_cdp_server-0.1.1-py3-none-any.whl:
Publisher:
publish.yml on xa1era/parsek-cdp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
parsek_cdp_server-0.1.1-py3-none-any.whl -
Subject digest:
319364c38003512c1053af8de647156b0b8ac07ef540aa636f1244549c1a10ba - Sigstore transparency entry: 2044510575
- Sigstore integration time:
-
Permalink:
xa1era/parsek-cdp@f05189f318c3395955d216e586fa4e45a606b28e -
Branch / Tag:
refs/tags/0.1.1 - Owner: https://github.com/xa1era
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f05189f318c3395955d216e586fa4e45a606b28e -
Trigger Event:
release
-
Statement type: