dp-cli
English | 中文
A powerful CLI for DrissionPage — browser automation, structured data extraction, network listening and more.
Features
- Anti-detection by default — not based on webdriver,
navigator.webdriverisfalse - Reuse your own browser —
--auto-connect(Chrome/Edge 144+, no CLI flag needed) or--port - Hybrid snapshot — a11y tree + Vimium-style clickable detection, catches icon-only buttons
and custom menu items the a11y tree misses; every element gets an
[N]ref with confidence markers (⚡medium,?low) dpx scan— fast Vimium-style listing of interactive elements (viewport-only mode available)- Powerful locator syntax — descriptive strings stable across navigation, plus
Playwright-style
pw:role=button[name="Submit"] >> nth=2chains - Structured data extraction —
extract+query+snapshotfor scraping list pages - Network listening — capture XHR/Fetch requests and response bodies
- Stealth patches —
dpx stealthbypasses common automation detections - Dual mode — browser control + pure HTTP requests
- Shadow-root / iframe — traverse directly without switching context
- Actionable auto-wait — click/fill wait for visible+stable+enabled+unoccluded, reports the blocking element on failure;
dialog-policyfor unattended dialog handling;batch --screenshot-on-failfor evidence - Fine-grained input —
keydown/keyup+ realmousemove/mousedown/mouseup/mousewheelCDP events;click --button/--modifiers/--click-count/--force - JSON output — all commands output JSON, AI-friendly
Installation
pip install dp-cli
dpx --help
入口冲突提示:DrissionPage 4.1.1.4+ 也注册了
dp命令(浏览器路径配置工具)。若dp被抢占(装包/升级顺序所致),用主入口dpx(独占命名)或python -m dp_cli.main;pip install --force-reinstall dp-cli可夺回dp。归属检测:dpx install --skills --check输出的entrypoint字段。
Agent skill(可选,推荐)
为 AI agent 安装完整使用指南(全部命令参考 + 工作流 playbook):
dpx install --skills # 装到 agent 的 skill 目录
npx skills add mofanx/dp-cli # 或走 skills CLI 渠道
claude plugin marketplace add mofanx/dp-cli # 或 Claude Code 插件市场
未安装也能用——skill 只是文档层;agent 可直接读 dpx --help 或 python -m dp_cli.catalog 自举。
升级后请刷新 skill:
pip install -U dp-cli后已装 skill 版本戳落后于 CLI—— 每条命令 stderr 会提示运行 'dpx install --skills' 更新(不污染 stdout JSON)。 执行dpx install --skills或dpx install --skills --check校验即可对齐。 版本戳相同但内容被篡改/过期时,--check同样检出差异文件清单。
Quick Start
# Auto-managed browser
dpx open https://example.com
dpx snapshot
dpx click "text:Login"
dpx fill "@name=username" admin
dpx press Enter
dpx close
# Connect to your own logged-in browser
google-chrome --remote-debugging-port=9222
dpx open https://example.com --port 9222
dpx snapshot
Connect to a Normally-Launched Chrome/Edge (Chrome/Edge 144+)
No --remote-debugging-port required. Chrome/Edge 144+ exposes opt-in remote debugging
via chrome://inspect (Chrome) or edge://inspect/#devices (Edge):
- Open your Chrome or Edge as usual (no special flags)
- Visit
chrome://inspect/#remote-debugging(Chrome) oredge://inspect/#devices(Edge) - Check "Allow remote debugging for this browser instance"
- Run
dpx open --auto-connect
dpx open --auto-connect # auto channel: sniffs Chrome stable → Edge stable
dpx open --auto-connect --channel edge # force Edge stable
dpx open --auto-connect --channel beta # Chrome beta
dpx open --auto-connect --probe-dir ~/my-profile # custom user-data-dir
How it works
Chrome/Edge 144+ in this mode exposes only a browser-level WebSocket and omits the HTTP
REST API (/json, /json/version, ...) that DrissionPage / puppeteer / Playwright
depend on. dp-cli transparently handles this:
- Reads
DevToolsActivePortfrom the user-data-dir → real CDP port - Probes the port — if
/json/versionis missing, identifies this as inspect mode - Spawns a local bridge (
python -m dp_cli.bridge) that:- Synthesizes the missing HTTP endpoints from CDP calls
- Multiplexes page-level CDP traffic over a single browser-level WebSocket
via
Target.attachToTarget(flatten=True)
- Points DrissionPage at the bridge. Subsequent
dpxcommands reuse the same bridge.
The bridge subprocess is registered in a shared registry (~/.dp_cli/bridges/) so all
sessions on the same profile reuse one authorized connection — dpx close keeps it
by default (only detaches your session). Use dpx close --stop-bridge or
DPX_CLOSE_STOPS_BRIDGE=1 for the old stop-on-close behavior, and dpx bridge list /
dpx bridge stop to inspect or terminate registered bridges directly.
dpx close never quits your browser (it's your browser, not dp's).
Caveats
- Chrome/Edge always shows an "Allow remote debugging" dialog per new WebSocket client.
Since bridge maintains one WebSocket and dpx commands share it, you confirm at most
once per
dpx open --auto-connect. - Works with whatever profile Chrome/Edge is actually using — same cookies, logins, history.
- Classic
--remote-debugging-port=9222mode still works unchanged viadpx open --port 9222.
Hybrid Snapshot (a11y + Vimium-style)
The default dpx snapshot fuses two element-discovery paths:
- Browser a11y tree via CDP — the structural skeleton (headings, lists, form roles,
explicit
<a>/<button>, anyrole="..."element). - Vimium-style clickable detection — a JS probe that flags icon-only buttons,
<div onclick>,[tabindex>=0],aria-selected,cursor:pointerelements, etc. that the a11y tree misses.
Results are deduplicated by backendNodeId and rendered with confidence markers:
| Marker | Confidence | Triggers |
|---|---|---|
| none | high | <a href>, <button>, <input>, role=button/link/..., contenteditable |
⚡ |
medium | onclick / jsaction / tabindex>=0 / aria-selected / <audio>/<video>, or cursor:pointer + heuristic (aria-label / icon child / small square / class keyword) — catches most React/Vue icon buttons |
? |
low | bare cursor:pointer / class keyword only (no other signals); hidden unless --include-low |
Output includes helpful context:
@top-left,@top-right,@center,@bottom… — position in the 9-region viewport grid(icon)— icon-only button (no visible label, has<svg>/<img>child)- Shadow DOM is traversed automatically (open shadow roots)
Every element gets an [N] ref usable in any command: dpx click "ref:5".
dpx snapshot # a11y + clickable (default); high + medium markers
dpx snapshot -i # interactive mode: only interactive elements
dpx snapshot -s ".main" # limit to specific area
dpx snapshot -p "data-test" # custom locator priority
dpx scan --viewport # only elements currently in viewport
dpx scan --confidence all # include low-confidence heuristics
dpx scan --confidence high # only the sure-thing clickables
dpx scan — fast clickable-only listing
When you only need "what can I click next?" without the full a11y tree:
dpx scan # full page, high+medium
dpx scan --viewport # only elements currently in viewport
dpx scan --confidence all # include low-confidence heuristics
dpx scan --confidence high # only the sure-thing clickables
Both snapshot and scan share the same [N] ref numbering per session, so
dpx click "ref:N" works regardless of which one produced the snapshot.
Playwright-style locators (pw: prefix)
Need semantic, role-based targeting on a fresh page (no snapshot required)?
Use the pw: prefix. Syntax mirrors Playwright, and chains with >>:
# By ARIA role (with accessible name — exact / substring / regex)
dpx click 'pw:role=button[name="Submit"]'
dpx click 'pw:role=button[name=/^Sign/i]'
dpx click 'pw:role=link[name=More]' # substring
# By visible text (exact / substring / regex)
dpx click 'pw:text="Login"' # exact
dpx click 'pw:text=Login' # substring (case-insensitive)
dpx click 'pw:text=/^log/i' # regex
# By form affordances
dpx fill 'pw:placeholder=Search…' "chatgpt"
dpx fill 'pw:label="Email"' "a@b.com"
dpx click 'pw:alt="Logo"'
dpx click 'pw:title="Close"'
dpx click 'pw:testid=submit-btn' # data-testid / data-test-id / data-test
# Chain with >> (each step narrows the scope)
dpx click 'pw:css=.sidebar >> role=listitem[name="Chat"] >> nth=2'
dpx click 'pw:css=li >> has-text="Python"'
dpx click 'pw:role=list >> nth=-1' # negative index = from end
# Raw css/xpath chunks mix freely
dpx click 'pw:xpath=//nav >> role=link[name=Docs]'
Matchers: role / text / label / placeholder / alt / title /
testid / css / xpath / nth / has-text / visible
Value forms: bare = substring, "quoted" = exact, /pattern/flags = regex
Visibility: role / text / has-text automatically skip elements hidden
via display:none, visibility:hidden, hidden attribute, or
aria-hidden="true" (matches Playwright semantics).
Shadow DOM: open shadow roots are traversed automatically.
Under the hood the matcher chain is evaluated in-page as JS, the target element
is tagged with a one-shot data-dp-ref attribute, and DrissionPage resolves it
by that attribute — bypassing stale classes / CSS Modules / dynamic XPath.
Anti-Detection (stealth)
Bypass navigator.webdriver, HeadlessChrome UA, empty plugins, SwiftShader WebGL,
chrome.runtime missing, and other common automation fingerprints.
# One-shot: connect + apply full stealth patches
dpx open --port 9322 --stealth
dpx goto https://bot.sannysoft.com/
# Or apply manually on an existing session (full preset by default)
dpx stealth
dpx stealth --preset mild # webdriver + UA only
dpx stealth --ua "Mozilla/5.0 ..." # custom UA
dpx stealth --feature webdriver --feature webgl # fine-grained
Recommended VPS Chrome flags (when connecting via SSH tunnel)
google-chrome --headless=new --remote-debugging-port=9222 \
--no-sandbox --disable-dev-shm-usage \
--disable-blink-features=AutomationControlled \
--user-data-dir=~/.config/google-chrome
# Then on local:
ssh -NL 9322:127.0.0.1:9222 vps
dpx open --port 9322 --stealth
Patched features (full preset): webdriver, UA, chrome.runtime, permissions,
plugins, languages, WebGL VENDOR/RENDERER, window.outerWidth/Height.
Patches are injected via Page.addScriptToEvaluateOnNewDocument — they persist across
navigations and frames. Advanced fingerprints (Canvas/Audio/font list) require a real
GPU or Xvfb environment.
Data Extraction (3-step workflow)
# 1. Discover CSS class names via noise-filtered content tree
dpx snapshot -i -s ".main"
# 2. Verify field selectors
dpx query "css:.item-title" --fields "text,loc"
# 3. Batch extract to CSV
dpx extract "css:.item-card" \
'{"title":"css:.item-title",
"price":"css:.item-price",
"tags":{"selector":"css:.tag","multi":true},
"url":{"selector":"css:a","attr":"href"}}' \
--limit 100 -o csv -f result.csv
New in 0.14
dpx mcp— MCP stdio server: 34 whitelisted tools over the existing JSON contract;evalgated behind--unsafe-eval. Claude Desktop:{"mcpServers":{"dpx":{"command":"dpx","args":["mcp"]}}}- Assertion coverage —
dpx assert-value <loc> <expect>;assert-countoperators (>=3/!=2/...);--noton everyassert-*;dpx wait --stable <loc> --for N(DOM quiet period) - netlog via daemon —
dpx daemon-starthosts the passive network log too;dpx requestsno longer requiresdpx serve
New in 0.13
- Batch form fill —
dpx fill-form "#u=admin" "css:#p=pw"or--data '{"#u":"x"}';per-field ok/fail 明细 - Cookie bulk import —
dpx cookies-import cookies.txt|-auto-sniffs Netscape dump / JSON /Cookie:header - Domain allowlist —
dpx intercept --allow-domain ex.comaborts all off-list requests (--allow-fileescapes file://) - Browserless read —
dpx read <url>fetches via curl_cffi (Accept: text/markdown+ llms.txt probing), no browser needed - Passive netlog —
dpx servebuffers ~500 requests →dpx requests/dpx request <id> - Session daemon —
dpx daemon-startthen commands run via unix socket, no per-cmd startup tax (DPX_DAEMON=1forces routing) - Timing waits —
dpx sleep N,dpx wait --popup(new tab id),dpx wait --download(dir-rescan fallback) - Select diagnostics — failed
dpx selectlists available option value(text)
Project Structure
dp_cli/
├── main.py # CLI entry point (~47 lines)
├── session.py # Browser session management + auto-connect bridge glue
├── bridge.py # chrome://inspect mode CDP bridge (python -m dp_cli.bridge)
├── bridge_manager.py # Bridge subprocess lifecycle + inspect-mode detection
├── stealth.py # Anti-detection JS patches (applied via CDP)
├── snapshot/ # a11y-tree snapshot & data extraction engine
├── output.py # JSON output helpers
└── commands/
├── _utils.py # Shared decorators & helpers
├── browser.py # open / goto / reload / close / list / stealth
├── snapshot_cmd.py # snapshot / extract / query / find / inspect
├── element.py # click / fill / select / hover / drag / check / upload / count
├── keyboard.py # press / type / scroll / scroll-to / autoscroll
├── page.py # screenshot / pdf / eval / wait / console / dialog
├── assert_cmd.py # assert-text / assert-url / assert-visible / assert-count
├── tab.py # tab-list / tab-new / tab-select / tab-close
├── storage.py # cookie-* / localstorage-* / sessionstorage-*
├── network.py # listen / listen-stop / http-get / http-post
└── misc.py # resize / maximize / state-save / state-load / config-set
Documentation
See skills/dp-cli/SKILL.md for full workflow guide and skills/dp-cli/references/commands.md for complete command reference. Exit-code contract: ERROR_CODES.md.
License
BSD-3-Clause
Metadata
Release files for dp-cli 0.14.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| dp_cli-0.14.0.tar.gz | 347.1 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| dp_cli-0.14.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 605.5 kB
Release files / dp_cli-0.14.0.tar.gz
| Download URL | dp_cli-0.14.0.tar.gz |
|---|---|
| Size | 347.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
292d4319d1339cd94da36c1da9222e97479670777d62c192d9f26bb88d6a1b67
|
|
BLAKE2b-256 checksum How to use checksums |
6337c0cfa60cf99c89873f51d9f1bb4f584ad3abf20d87b7116d0e2d367ac4d1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.15
|
Release files / dp_cli-0.14.0-py3-none-any.whl
| Download URL | dp_cli-0.14.0-py3-none-any.whl |
|---|---|
| Size | 258.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
28aca5b633dcdcc6c163cf2e3b1c2466a8c1182e789bdffd115cc3b16d3318ce
|
|
BLAKE2b-256 checksum How to use checksums |
736246210aba81d426cf180502e79f4aa0edbb0e3c8ceb3c7710c964d2b58f53
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.15
|
Security for dp-cli 0.14.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.