patchright-cli 0.3.1__tar.gz → 0.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- patchright_cli-0.4.0/.claude-plugin/marketplace.json +21 -0
- patchright_cli-0.4.0/.claude-plugin/skills/browser-automation.json +5 -0
- {patchright_cli-0.3.1 → patchright_cli-0.4.0}/PKG-INFO +1 -1
- {patchright_cli-0.3.1 → patchright_cli-0.4.0}/pyproject.toml +13 -1
- {patchright_cli-0.3.1 → patchright_cli-0.4.0}/skills/patchright-cli/SKILL.md +49 -10
- {patchright_cli-0.3.1 → patchright_cli-0.4.0}/src/patchright_cli/__init__.py +1 -1
- {patchright_cli-0.3.1 → patchright_cli-0.4.0}/src/patchright_cli/cli.py +17 -20
- patchright_cli-0.4.0/src/patchright_cli/daemon.py +1462 -0
- patchright_cli-0.4.0/src/patchright_cli/ref_registry.py +74 -0
- patchright_cli-0.4.0/src/patchright_cli/snapshot.py +46 -0
- patchright_cli-0.4.0/tests/__init__.py +0 -0
- patchright_cli-0.4.0/tests/fixture.html +30 -0
- patchright_cli-0.4.0/tests/test_daemon_handlers.py +124 -0
- patchright_cli-0.4.0/tests/test_e2e.py +144 -0
- patchright_cli-0.4.0/tests/test_ref_registry.py +75 -0
- {patchright_cli-0.3.1 → patchright_cli-0.4.0}/uv.lock +156 -1
- patchright_cli-0.3.1/src/patchright_cli/daemon.py +0 -1094
- patchright_cli-0.3.1/src/patchright_cli/snapshot.py +0 -346
- {patchright_cli-0.3.1 → patchright_cli-0.4.0}/.github/workflows/publish.yml +0 -0
- {patchright_cli-0.3.1 → patchright_cli-0.4.0}/.gitignore +0 -0
- {patchright_cli-0.3.1 → patchright_cli-0.4.0}/.pre-commit-config.yaml +0 -0
- {patchright_cli-0.3.1 → patchright_cli-0.4.0}/CLAUDE.md +0 -0
- {patchright_cli-0.3.1 → patchright_cli-0.4.0}/CONTRIBUTING.md +0 -0
- {patchright_cli-0.3.1 → patchright_cli-0.4.0}/LICENSE +0 -0
- {patchright_cli-0.3.1 → patchright_cli-0.4.0}/README.md +0 -0
- {patchright_cli-0.3.1 → patchright_cli-0.4.0}/docs/installation.md +0 -0
- {patchright_cli-0.3.1 → patchright_cli-0.4.0}/patchright-cli +0 -0
- {patchright_cli-0.3.1 → patchright_cli-0.4.0}/patchright-cli.cmd +0 -0
- {patchright_cli-0.3.1 → patchright_cli-0.4.0}/src/patchright_cli/__main__.py +0 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "patchright-cli",
|
|
3
|
+
"owner": {
|
|
4
|
+
"name": "zpahai"
|
|
5
|
+
},
|
|
6
|
+
"metadata": {
|
|
7
|
+
"description": "Anti-detect browser automation CLI using Patchright (undetected Playwright fork)",
|
|
8
|
+
"version": "0.4.0"
|
|
9
|
+
},
|
|
10
|
+
"plugins": [
|
|
11
|
+
{
|
|
12
|
+
"name": "patchright-cli",
|
|
13
|
+
"description": "Anti-detect browser automation CLI for AI agents",
|
|
14
|
+
"source": "./",
|
|
15
|
+
"skills": [
|
|
16
|
+
"./skills/patchright-cli",
|
|
17
|
+
"./.claude-plugin/skills/browser-automation"
|
|
18
|
+
]
|
|
19
|
+
}
|
|
20
|
+
]
|
|
21
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: patchright-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Anti-detect browser automation CLI using Patchright (undetected Playwright fork)
|
|
5
5
|
Project-URL: Homepage, https://github.com/AhaiMk01/patchright-cli
|
|
6
6
|
Project-URL: Repository, https://github.com/AhaiMk01/patchright-cli
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "patchright-cli"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.4.0"
|
|
4
4
|
description = "Anti-detect browser automation CLI using Patchright (undetected Playwright fork)"
|
|
5
5
|
license = "Apache-2.0"
|
|
6
6
|
requires-python = ">=3.10"
|
|
@@ -43,6 +43,18 @@ build-backend = "hatchling.build"
|
|
|
43
43
|
[tool.hatch.build.targets.wheel]
|
|
44
44
|
packages = ["src/patchright_cli"]
|
|
45
45
|
|
|
46
|
+
[tool.pytest.ini_options]
|
|
47
|
+
asyncio_mode = "auto"
|
|
48
|
+
markers = [
|
|
49
|
+
"e2e: marks tests that launch a real browser",
|
|
50
|
+
]
|
|
51
|
+
|
|
52
|
+
[dependency-groups]
|
|
53
|
+
dev = [
|
|
54
|
+
"pytest>=8.0",
|
|
55
|
+
"pytest-asyncio>=0.23",
|
|
56
|
+
]
|
|
57
|
+
|
|
46
58
|
[tool.ruff]
|
|
47
59
|
target-version = "py310"
|
|
48
60
|
line-length = 120
|
|
@@ -7,6 +7,19 @@ description: Anti-detect browser automation using Patchright (undetected Playwri
|
|
|
7
7
|
|
|
8
8
|
patchright-cli drives a real Chrome browser that passes bot detection (Cloudflare, Akamai, etc.). It works as a CLI: you issue commands, get back page state. This is the tool to reach for whenever regular Playwright or Chrome DevTools gets blocked.
|
|
9
9
|
|
|
10
|
+
## What's new in v0.4.0
|
|
11
|
+
|
|
12
|
+
- **Native accessibility snapshots** — uses Playwright's built-in `aria_snapshot()` instead of custom DOM injection. More accurate and immune to page-script interference.
|
|
13
|
+
- **Smart link clicks** — `click` on a link now navigates directly via `goto`, avoiding sticky-header timeouts and `target="_blank"` silences.
|
|
14
|
+
- **Custom history stack** — `go-back` and `go-forward` now use an internal history tracker instead of the browser History API, so they work reliably on anti-detect sites that spoof history.
|
|
15
|
+
- **Scroll & wait commands** — `scroll`, `scroll-to`, `wait`, and `wait-for` are now available.
|
|
16
|
+
- **`text` command** — quickly grab text content of an element by ref or CSS selector.
|
|
17
|
+
- **Cookie bulk import/export** — `cookie-import` and `cookie-export` for transferring cookie jars via JSON.
|
|
18
|
+
- **Authenticated proxy support** — `--proxy=http://user:pass@host:port` is parsed automatically; credentials are injected via `Proxy-Authorization`.
|
|
19
|
+
- **Daemon auto-restart** — the daemon respawns automatically if it isn't running, even for commands other than `open`.
|
|
20
|
+
- **Idle timeout** — daemon shuts itself down after 5 minutes of inactivity to free resources.
|
|
21
|
+
- **Test suite** — unit + async handler + e2e tests are included in `tests/`.
|
|
22
|
+
|
|
10
23
|
## How it works: the snapshot-driven loop
|
|
11
24
|
|
|
12
25
|
Every interaction follows the same cycle:
|
|
@@ -16,7 +29,7 @@ open browser → snapshot → read refs → interact → snapshot again → repe
|
|
|
16
29
|
```
|
|
17
30
|
|
|
18
31
|
1. **Open** a browser session — this launches a real Chrome window
|
|
19
|
-
2. **Snapshot** the page — this
|
|
32
|
+
2. **Snapshot** the page — this uses Playwright's accessibility tree and assigns refs (`e1`, `e2`, ...) to interactive elements
|
|
20
33
|
3. **Read the snapshot** — it's a YAML file showing the element tree with refs
|
|
21
34
|
4. **Interact** using refs — `click e5`, `fill e3 "hello"`, etc.
|
|
22
35
|
5. **Check the result** — most commands auto-snapshot, so you get updated refs
|
|
@@ -83,7 +96,7 @@ These go before the command:
|
|
|
83
96
|
--headless # Run headless (default: headed — headed is less detectable)
|
|
84
97
|
--persistent # Use persistent profile (keeps cookies/storage across sessions)
|
|
85
98
|
--profile=/path # Custom profile directory
|
|
86
|
-
--proxy=<url> # Proxy server (http, https, socks5)
|
|
99
|
+
--proxy=<url> # Proxy server (http, https, socks5) — supports user:pass@host auth
|
|
87
100
|
-s=mysession # Named session (default: "default")
|
|
88
101
|
--port=9322 # Custom daemon port (default: 9321)
|
|
89
102
|
```
|
|
@@ -102,6 +115,7 @@ patchright-cli open --headless # Headless mode
|
|
|
102
115
|
patchright-cli open --profile=/path/to/dir # Custom profile directory
|
|
103
116
|
patchright-cli --proxy=http://host:port open # Route traffic through HTTP proxy
|
|
104
117
|
patchright-cli --proxy=socks5://host:port open # SOCKS5 proxy
|
|
118
|
+
patchright-cli --proxy=http://user:pass@host:port open # Authenticated proxy
|
|
105
119
|
patchright-cli close # Close session
|
|
106
120
|
```
|
|
107
121
|
|
|
@@ -109,9 +123,11 @@ patchright-cli close # Close session
|
|
|
109
123
|
|
|
110
124
|
```bash
|
|
111
125
|
patchright-cli goto https://example.com
|
|
112
|
-
patchright-cli go-back
|
|
126
|
+
patchright-cli go-back # Uses internal history stack
|
|
113
127
|
patchright-cli go-forward
|
|
114
128
|
patchright-cli reload
|
|
129
|
+
patchright-cli url # Print current URL
|
|
130
|
+
patchright-cli title # Print page title
|
|
115
131
|
```
|
|
116
132
|
|
|
117
133
|
### Snapshots
|
|
@@ -138,6 +154,8 @@ patchright-cli hover e4
|
|
|
138
154
|
patchright-cli drag e2 e8 # Drag element to target
|
|
139
155
|
```
|
|
140
156
|
|
|
157
|
+
`click` is smart about links: if the element (or an ancestor) is an `<a>` tag, the CLI navigates directly instead of performing a DOM click. This avoids sticky-header overlay timeouts and `target="_blank"` silences.
|
|
158
|
+
|
|
141
159
|
### Form input
|
|
142
160
|
|
|
143
161
|
```bash
|
|
@@ -152,6 +170,13 @@ patchright-cli uncheck e12
|
|
|
152
170
|
|
|
153
171
|
`fill` targets a specific input by ref and replaces its contents. `type` types via the keyboard into whatever is focused.
|
|
154
172
|
|
|
173
|
+
### Text extraction
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
patchright-cli text e5 # Get text content by ref
|
|
177
|
+
patchright-cli text "h1" # Or by raw CSS selector
|
|
178
|
+
```
|
|
179
|
+
|
|
155
180
|
### Screenshots
|
|
156
181
|
|
|
157
182
|
```bash
|
|
@@ -163,6 +188,16 @@ patchright-cli screenshot --full-page # Full scrollable page
|
|
|
163
188
|
|
|
164
189
|
Screenshots save to `.patchright-cli/` in the current directory.
|
|
165
190
|
|
|
191
|
+
### Scroll & wait
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
patchright-cli scroll 0 200 # Scroll by (dx, dy) pixels
|
|
195
|
+
patchright-cli scroll-to e5 # Scroll element into view
|
|
196
|
+
patchright-cli wait 500 # Wait N milliseconds
|
|
197
|
+
patchright-cli wait-for e5 # Wait until element is visible
|
|
198
|
+
patchright-cli wait-for e5 --state=hidden # Wait until hidden
|
|
199
|
+
```
|
|
200
|
+
|
|
166
201
|
### Keyboard and mouse
|
|
167
202
|
|
|
168
203
|
```bash
|
|
@@ -234,7 +269,7 @@ patchright-cli --proxy=http://host:port open https://example.com
|
|
|
234
269
|
# SOCKS5 proxy
|
|
235
270
|
patchright-cli --proxy=socks5://host:port open https://example.com
|
|
236
271
|
|
|
237
|
-
# Authenticated proxy
|
|
272
|
+
# Authenticated proxy (credentials are parsed and injected automatically)
|
|
238
273
|
patchright-cli --proxy=http://user:pass@host:port open https://example.com
|
|
239
274
|
|
|
240
275
|
# Combine with persistent profile and named session
|
|
@@ -275,14 +310,14 @@ patchright-cli eval --file=/tmp/extract.js
|
|
|
275
310
|
|
|
276
311
|
### Waiting for dynamic content
|
|
277
312
|
|
|
278
|
-
The page may not be fully loaded when you snapshot. If elements are missing, try:
|
|
279
|
-
|
|
280
313
|
```bash
|
|
281
|
-
#
|
|
282
|
-
|
|
283
|
-
|
|
314
|
+
# Wait for an element to appear
|
|
315
|
+
patchright-cli wait-for e12
|
|
316
|
+
|
|
317
|
+
# Or wait a fixed time
|
|
318
|
+
patchright-cli wait 1000
|
|
284
319
|
|
|
285
|
-
#
|
|
320
|
+
# If you need a custom condition, use run-code
|
|
286
321
|
cat > /tmp/wait.js << 'JSEOF'
|
|
287
322
|
for (let i = 0; i < 30; i++) {
|
|
288
323
|
if (document.querySelector('.results-loaded')) return true;
|
|
@@ -334,6 +369,8 @@ patchright-cli cookie-set session_id abc123 # Set cookie (current pa
|
|
|
334
369
|
patchright-cli cookie-set token xyz --domain=example.com --path=/ --httpOnly --secure --sameSite=Lax --expires=1735689600
|
|
335
370
|
patchright-cli cookie-delete session_id
|
|
336
371
|
patchright-cli cookie-clear # Clear all
|
|
372
|
+
patchright-cli cookie-export cookies.json # Export all cookies to JSON
|
|
373
|
+
patchright-cli cookie-import cookies.json # Import cookies from JSON
|
|
337
374
|
```
|
|
338
375
|
|
|
339
376
|
### localStorage / sessionStorage
|
|
@@ -441,6 +478,8 @@ patchright-cli delete-data # Delete default session's profile
|
|
|
441
478
|
patchright-cli -s=mysession delete-data # Delete named session's profile
|
|
442
479
|
```
|
|
443
480
|
|
|
481
|
+
The daemon auto-starts on the first command and auto-shuts down after 5 minutes of inactivity. If it ever crashes, the next command you run will respawn it automatically.
|
|
482
|
+
|
|
444
483
|
---
|
|
445
484
|
|
|
446
485
|
## Anti-detect notes
|
|
@@ -72,6 +72,7 @@ COMMANDS_HELP = {
|
|
|
72
72
|
"uncheck": "uncheck <ref> Uncheck checkbox/radio",
|
|
73
73
|
"snapshot": "snapshot [ref] Take accessibility snapshot",
|
|
74
74
|
"eval": "eval <expr> Evaluate JavaScript [--file=F or stdin]",
|
|
75
|
+
"text": "text <ref|selector> Get text content of element",
|
|
75
76
|
"screenshot": "screenshot [ref] Save screenshot [--full-page] [--filename=F]",
|
|
76
77
|
"drag": "drag <from> <to> Drag element to target",
|
|
77
78
|
"close": "close Close browser session",
|
|
@@ -79,6 +80,8 @@ COMMANDS_HELP = {
|
|
|
79
80
|
"go-back": "go-back Go back",
|
|
80
81
|
"go-forward": "go-forward Go forward",
|
|
81
82
|
"reload": "reload Reload page",
|
|
83
|
+
"url": "url Print current URL",
|
|
84
|
+
"title": "title Print page title",
|
|
82
85
|
# Keyboard
|
|
83
86
|
"press": "press <key> Press key",
|
|
84
87
|
"keydown": "keydown <key> Key down",
|
|
@@ -88,6 +91,11 @@ COMMANDS_HELP = {
|
|
|
88
91
|
"mousedown": "mousedown [button] Mouse button down",
|
|
89
92
|
"mouseup": "mouseup [button] Mouse button up",
|
|
90
93
|
"mousewheel": "mousewheel <dx> <dy> Scroll mouse wheel",
|
|
94
|
+
# Scroll & Wait
|
|
95
|
+
"scroll": "scroll <dx> <dy> Scroll by pixel offset",
|
|
96
|
+
"scroll-to": "scroll-to <ref> Scroll element into view",
|
|
97
|
+
"wait": "wait <ms> Wait for milliseconds",
|
|
98
|
+
"wait-for": "wait-for <ref> Wait for element to appear [--state=hidden]",
|
|
91
99
|
# Tabs
|
|
92
100
|
"tab-list": "tab-list List tabs",
|
|
93
101
|
"tab-new": "tab-new [url] Open new tab",
|
|
@@ -99,6 +107,8 @@ COMMANDS_HELP = {
|
|
|
99
107
|
"cookie-set": "cookie-set <n> <v> Set cookie [--domain --path --expires --httpOnly --secure --sameSite]",
|
|
100
108
|
"cookie-delete": "cookie-delete <name> Delete cookie",
|
|
101
109
|
"cookie-clear": "cookie-clear Clear all cookies",
|
|
110
|
+
"cookie-import": "cookie-import <file> Import cookies from JSON",
|
|
111
|
+
"cookie-export": "cookie-export [file] Export cookies to JSON",
|
|
102
112
|
"localstorage-list": "localstorage-list List localStorage",
|
|
103
113
|
"localstorage-get": "localstorage-get <k> Get localStorage item",
|
|
104
114
|
"localstorage-set": "localstorage-set <k> <v> Set localStorage item",
|
|
@@ -177,14 +187,16 @@ def _print_help():
|
|
|
177
187
|
"uncheck",
|
|
178
188
|
"snapshot",
|
|
179
189
|
"eval",
|
|
190
|
+
"text",
|
|
180
191
|
"screenshot",
|
|
181
192
|
"drag",
|
|
182
193
|
"close",
|
|
183
194
|
],
|
|
184
195
|
),
|
|
185
|
-
("Navigation", ["go-back", "go-forward", "reload"]),
|
|
196
|
+
("Navigation", ["go-back", "go-forward", "reload", "url", "title"]),
|
|
186
197
|
("Keyboard", ["press", "keydown", "keyup"]),
|
|
187
198
|
("Mouse", ["mousemove", "mousedown", "mouseup", "mousewheel"]),
|
|
199
|
+
("Scroll & Wait", ["scroll", "scroll-to", "wait", "wait-for"]),
|
|
188
200
|
("Tabs", ["tab-list", "tab-new", "tab-close", "tab-select"]),
|
|
189
201
|
("Dialog", ["dialog-accept", "dialog-dismiss"]),
|
|
190
202
|
("Upload/Resize", ["upload", "resize"]),
|
|
@@ -197,6 +209,8 @@ def _print_help():
|
|
|
197
209
|
"cookie-set",
|
|
198
210
|
"cookie-delete",
|
|
199
211
|
"cookie-clear",
|
|
212
|
+
"cookie-import",
|
|
213
|
+
"cookie-export",
|
|
200
214
|
"localstorage-list",
|
|
201
215
|
"localstorage-get",
|
|
202
216
|
"localstorage-set",
|
|
@@ -340,26 +354,9 @@ def main():
|
|
|
340
354
|
if proxy:
|
|
341
355
|
options["proxy"] = proxy
|
|
342
356
|
|
|
343
|
-
# Ensure daemon is running (auto-start for
|
|
357
|
+
# Ensure daemon is running (auto-start for all commands)
|
|
344
358
|
try:
|
|
345
|
-
|
|
346
|
-
ensure_daemon_running(port, headless)
|
|
347
|
-
else:
|
|
348
|
-
# Try connecting first; if fails, tell user to open
|
|
349
|
-
import socket as _socket
|
|
350
|
-
|
|
351
|
-
sock = _socket.socket(_socket.AF_INET, _socket.SOCK_STREAM)
|
|
352
|
-
try:
|
|
353
|
-
sock.settimeout(1)
|
|
354
|
-
sock.connect(("127.0.0.1", port))
|
|
355
|
-
except (ConnectionRefusedError, OSError, TimeoutError):
|
|
356
|
-
click.echo(
|
|
357
|
-
f"Daemon is not running on port {port}. Run 'patchright-cli open' first.",
|
|
358
|
-
err=True,
|
|
359
|
-
)
|
|
360
|
-
sys.exit(1)
|
|
361
|
-
finally:
|
|
362
|
-
sock.close()
|
|
359
|
+
ensure_daemon_running(port, headless)
|
|
363
360
|
except RuntimeError as e:
|
|
364
361
|
click.echo(str(e), err=True)
|
|
365
362
|
sys.exit(1)
|