cdp-toolkit 1.1.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.
- cdp_toolkit-1.1.0/PKG-INFO +52 -0
- cdp_toolkit-1.1.0/README.md +39 -0
- cdp_toolkit-1.1.0/pyproject.toml +20 -0
- cdp_toolkit-1.1.0/setup.cfg +4 -0
- cdp_toolkit-1.1.0/src/__init__.py +0 -0
- cdp_toolkit-1.1.0/src/cdp_client.py +144 -0
- cdp_toolkit-1.1.0/src/cdp_toolkit.egg-info/PKG-INFO +52 -0
- cdp_toolkit-1.1.0/src/cdp_toolkit.egg-info/SOURCES.txt +9 -0
- cdp_toolkit-1.1.0/src/cdp_toolkit.egg-info/dependency_links.txt +1 -0
- cdp_toolkit-1.1.0/src/cdp_toolkit.egg-info/top_level.txt +2 -0
- cdp_toolkit-1.1.0/tests/test_cdp.py +64 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cdp-toolkit
|
|
3
|
+
Version: 1.1.0
|
|
4
|
+
Summary: Chrome DevTools Protocol automation toolkit
|
|
5
|
+
Author: aaameobius-crypto
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/aaameobius-crypto/cdp-toolkit
|
|
8
|
+
Keywords: cdp,chrome,automation,browser
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Requires-Python: >=3.8
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
|
|
14
|
+
# CDP Toolkit
|
|
15
|
+
|
|
16
|
+
> Chrome DevTools Protocol automation without external dependencies
|
|
17
|
+
|
|
18
|
+
## Features
|
|
19
|
+
|
|
20
|
+
- CDPClient — HTTP endpoint for tab management (list, create, close, activate)
|
|
21
|
+
- CDPMouseEvents — mouse click, release, move params
|
|
22
|
+
- CDPInput — text injection, key events, React/Vue native setter JS
|
|
23
|
+
- CDPNavigation — navigate, evaluate JS, screenshot params
|
|
24
|
+
- Pure Python stdlib — no playwright, no selenium, no puppeteer
|
|
25
|
+
|
|
26
|
+
## Quick Start
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
from cdp_client import CDPClient, CDPInput
|
|
30
|
+
|
|
31
|
+
client = CDPClient("127.0.0.1", 9222)
|
|
32
|
+
targets = client.list_targets()
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## React Form Fill
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
from cdp_client import CDPInput
|
|
39
|
+
|
|
40
|
+
js = CDPInput.native_setter_js("#email", "user@example.com")
|
|
41
|
+
# Send via CDP Runtime.evaluate
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Tests
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
python -m pytest tests/ -v
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## License
|
|
51
|
+
|
|
52
|
+
MIT
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# CDP Toolkit
|
|
2
|
+
|
|
3
|
+
> Chrome DevTools Protocol automation without external dependencies
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- CDPClient — HTTP endpoint for tab management (list, create, close, activate)
|
|
8
|
+
- CDPMouseEvents — mouse click, release, move params
|
|
9
|
+
- CDPInput — text injection, key events, React/Vue native setter JS
|
|
10
|
+
- CDPNavigation — navigate, evaluate JS, screenshot params
|
|
11
|
+
- Pure Python stdlib — no playwright, no selenium, no puppeteer
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```python
|
|
16
|
+
from cdp_client import CDPClient, CDPInput
|
|
17
|
+
|
|
18
|
+
client = CDPClient("127.0.0.1", 9222)
|
|
19
|
+
targets = client.list_targets()
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## React Form Fill
|
|
23
|
+
|
|
24
|
+
```python
|
|
25
|
+
from cdp_client import CDPInput
|
|
26
|
+
|
|
27
|
+
js = CDPInput.native_setter_js("#email", "user@example.com")
|
|
28
|
+
# Send via CDP Runtime.evaluate
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Tests
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
python -m pytest tests/ -v
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## License
|
|
38
|
+
|
|
39
|
+
MIT
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=64"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "cdp-toolkit"
|
|
7
|
+
version = "1.1.0"
|
|
8
|
+
description = "Chrome DevTools Protocol automation toolkit"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = {text = "MIT"}
|
|
11
|
+
requires-python = ">=3.8"
|
|
12
|
+
authors = [{name = "aaameobius-crypto"}]
|
|
13
|
+
keywords = ["cdp", "chrome", "automation", "browser"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Programming Language :: Python :: 3",
|
|
16
|
+
"License :: OSI Approved :: MIT License",
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
[project.urls]
|
|
20
|
+
Homepage = "https://github.com/aaameobius-crypto/cdp-toolkit"
|
|
File without changes
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"""CDP Toolkit — Chrome DevTools Protocol automation without external deps."""
|
|
2
|
+
import json
|
|
3
|
+
import socket
|
|
4
|
+
import base64
|
|
5
|
+
import urllib.request
|
|
6
|
+
from typing import Any, Dict, Optional, List
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class CDPClient:
|
|
10
|
+
"""Minimal CDP client using raw WebSocket protocol."""
|
|
11
|
+
|
|
12
|
+
def __init__(self, host: str = "127.0.0.1", port: int = 9222):
|
|
13
|
+
self.host = host
|
|
14
|
+
self.port = port
|
|
15
|
+
self.msg_id = 0
|
|
16
|
+
self.ws = None
|
|
17
|
+
|
|
18
|
+
def _get_ws_url(self) -> str:
|
|
19
|
+
"""Get WebSocket debugger URL from CDP HTTP endpoint."""
|
|
20
|
+
url = f"http://{self.host}:{self.port}/json"
|
|
21
|
+
resp = urllib.request.urlopen(url, timeout=5)
|
|
22
|
+
tabs = json.loads(resp.read())
|
|
23
|
+
for tab in tabs:
|
|
24
|
+
if tab.get("type") == "page":
|
|
25
|
+
return tab["webSocketDebuggerUrl"]
|
|
26
|
+
raise ConnectionError("No page tab found")
|
|
27
|
+
|
|
28
|
+
def _next_id(self) -> int:
|
|
29
|
+
self.msg_id += 1
|
|
30
|
+
return self.msg_id
|
|
31
|
+
|
|
32
|
+
def list_targets(self) -> List[Dict]:
|
|
33
|
+
"""List all browser targets via HTTP endpoint."""
|
|
34
|
+
url = f"http://{self.host}:{self.port}/json"
|
|
35
|
+
resp = urllib.request.urlopen(url, timeout=5)
|
|
36
|
+
return json.loads(resp.read())
|
|
37
|
+
|
|
38
|
+
def create_target(self, url: str) -> Dict:
|
|
39
|
+
"""Create a new browser tab."""
|
|
40
|
+
encoded = urllib.parse.quote(url, safe="")
|
|
41
|
+
req = urllib.request.Request(
|
|
42
|
+
f"http://{self.host}:{self.port}/json/new?{encoded}",
|
|
43
|
+
method="PUT"
|
|
44
|
+
)
|
|
45
|
+
resp = urllib.request.urlopen(req, timeout=10)
|
|
46
|
+
return json.loads(resp.read())
|
|
47
|
+
|
|
48
|
+
def close_target(self, target_id: str) -> bool:
|
|
49
|
+
"""Close a browser tab by target ID."""
|
|
50
|
+
req = urllib.request.Request(
|
|
51
|
+
f"http://{self.host}:{self.port}/json/close/{target_id}",
|
|
52
|
+
method="GET"
|
|
53
|
+
)
|
|
54
|
+
resp = urllib.request.urlopen(req, timeout=5)
|
|
55
|
+
result = json.loads(resp.read())
|
|
56
|
+
return result.get("result", False)
|
|
57
|
+
|
|
58
|
+
def activate_target(self, target_id: str) -> bool:
|
|
59
|
+
"""Activate a browser tab."""
|
|
60
|
+
req = urllib.request.Request(
|
|
61
|
+
f"http://{self.host}:{self.port}/json/activate/{target_id}",
|
|
62
|
+
method="GET"
|
|
63
|
+
)
|
|
64
|
+
resp = urllib.request.urlopen(req, timeout=5)
|
|
65
|
+
return True
|
|
66
|
+
|
|
67
|
+
def get_version(self) -> Dict:
|
|
68
|
+
"""Get browser version info."""
|
|
69
|
+
url = f"http://{self.host}:{self.port}/json/version"
|
|
70
|
+
resp = urllib.request.urlopen(url, timeout=5)
|
|
71
|
+
return json.loads(resp.read())
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class CDPMouseEvents:
|
|
75
|
+
"""CDP mouse event helpers — calculates coordinates for clicks."""
|
|
76
|
+
|
|
77
|
+
@staticmethod
|
|
78
|
+
def click_params(x: int, y: int, button: str = "left", click_count: int = 1) -> Dict:
|
|
79
|
+
return {
|
|
80
|
+
"type": "mousePressed",
|
|
81
|
+
"x": x,
|
|
82
|
+
"y": y,
|
|
83
|
+
"button": button,
|
|
84
|
+
"clickCount": click_count,
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
@staticmethod
|
|
88
|
+
def release_params(x: int, y: int, button: str = "left") -> Dict:
|
|
89
|
+
return {
|
|
90
|
+
"type": "mouseReleased",
|
|
91
|
+
"x": x,
|
|
92
|
+
"y": y,
|
|
93
|
+
"button": button,
|
|
94
|
+
"clickCount": 1,
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
@staticmethod
|
|
98
|
+
def move_params(x: int, y: int) -> Dict:
|
|
99
|
+
return {"type": "mouseMoved", "x": x, "y": y}
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class CDPInput:
|
|
103
|
+
"""CDP input helpers for text injection and key events."""
|
|
104
|
+
|
|
105
|
+
@staticmethod
|
|
106
|
+
def insert_text_params(text: str) -> Dict:
|
|
107
|
+
return {"text": text}
|
|
108
|
+
|
|
109
|
+
@staticmethod
|
|
110
|
+
def key_event_params(key: str, type: str = "keyDown") -> Dict:
|
|
111
|
+
return {"type": type, "key": key}
|
|
112
|
+
|
|
113
|
+
@staticmethod
|
|
114
|
+
def native_setter_js(selector: str, value: str) -> str:
|
|
115
|
+
"""JavaScript for React/Vue native value setter."""
|
|
116
|
+
return f"""
|
|
117
|
+
(function() {{
|
|
118
|
+
var el = document.querySelector('{selector}');
|
|
119
|
+
if (!el) return 'Element not found';
|
|
120
|
+
var nativeInputValueSetter = Object.getOwnPropertyDescriptor(
|
|
121
|
+
window.HTMLInputElement.prototype, 'value'
|
|
122
|
+
).set;
|
|
123
|
+
nativeInputValueSetter.call(el, '{value}');
|
|
124
|
+
el.dispatchEvent(new Event('input', {{ bubbles: true }}));
|
|
125
|
+
el.dispatchEvent(new Event('change', {{ bubbles: true }}));
|
|
126
|
+
return 'OK';
|
|
127
|
+
}})()
|
|
128
|
+
"""
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
class CDPNavigation:
|
|
132
|
+
"""CDP navigation helpers."""
|
|
133
|
+
|
|
134
|
+
@staticmethod
|
|
135
|
+
def navigate_params(url: str) -> Dict:
|
|
136
|
+
return {"url": url}
|
|
137
|
+
|
|
138
|
+
@staticmethod
|
|
139
|
+
def evaluate_params(expression: str) -> Dict:
|
|
140
|
+
return {"expression": expression, "returnByValue": True}
|
|
141
|
+
|
|
142
|
+
@staticmethod
|
|
143
|
+
def screenshot_params(format: str = "png", quality: int = 80) -> Dict:
|
|
144
|
+
return {"format": format, "quality": quality}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cdp-toolkit
|
|
3
|
+
Version: 1.1.0
|
|
4
|
+
Summary: Chrome DevTools Protocol automation toolkit
|
|
5
|
+
Author: aaameobius-crypto
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/aaameobius-crypto/cdp-toolkit
|
|
8
|
+
Keywords: cdp,chrome,automation,browser
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Requires-Python: >=3.8
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
|
|
14
|
+
# CDP Toolkit
|
|
15
|
+
|
|
16
|
+
> Chrome DevTools Protocol automation without external dependencies
|
|
17
|
+
|
|
18
|
+
## Features
|
|
19
|
+
|
|
20
|
+
- CDPClient — HTTP endpoint for tab management (list, create, close, activate)
|
|
21
|
+
- CDPMouseEvents — mouse click, release, move params
|
|
22
|
+
- CDPInput — text injection, key events, React/Vue native setter JS
|
|
23
|
+
- CDPNavigation — navigate, evaluate JS, screenshot params
|
|
24
|
+
- Pure Python stdlib — no playwright, no selenium, no puppeteer
|
|
25
|
+
|
|
26
|
+
## Quick Start
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
from cdp_client import CDPClient, CDPInput
|
|
30
|
+
|
|
31
|
+
client = CDPClient("127.0.0.1", 9222)
|
|
32
|
+
targets = client.list_targets()
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## React Form Fill
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
from cdp_client import CDPInput
|
|
39
|
+
|
|
40
|
+
js = CDPInput.native_setter_js("#email", "user@example.com")
|
|
41
|
+
# Send via CDP Runtime.evaluate
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Tests
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
python -m pytest tests/ -v
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## License
|
|
51
|
+
|
|
52
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
import os
|
|
3
|
+
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "src"))
|
|
4
|
+
from cdp_client import CDPClient, CDPMouseEvents, CDPInput, CDPNavigation
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def test_cdp_client_init():
|
|
8
|
+
client = CDPClient("127.0.0.1", 9222)
|
|
9
|
+
assert client.host == "127.0.0.1"
|
|
10
|
+
assert client.port == 9222
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def test_mouse_click_params():
|
|
14
|
+
params = CDPMouseEvents.click_params(100, 200)
|
|
15
|
+
assert params["x"] == 100
|
|
16
|
+
assert params["y"] == 200
|
|
17
|
+
assert params["type"] == "mousePressed"
|
|
18
|
+
assert params["button"] == "left"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def test_mouse_release_params():
|
|
22
|
+
params = CDPMouseEvents.release_params(100, 200)
|
|
23
|
+
assert params["type"] == "mouseReleased"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def test_mouse_move_params():
|
|
27
|
+
params = CDPMouseEvents.move_params(50, 75)
|
|
28
|
+
assert params["x"] == 50
|
|
29
|
+
assert params["type"] == "mouseMoved"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def test_insert_text():
|
|
33
|
+
params = CDPInput.insert_text_params("hello world")
|
|
34
|
+
assert params["text"] == "hello world"
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def test_key_event():
|
|
38
|
+
params = CDPInput.key_event_params("Enter", "keyDown")
|
|
39
|
+
assert params["key"] == "Enter"
|
|
40
|
+
assert params["type"] == "keyDown"
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def test_native_setter_js():
|
|
44
|
+
js = CDPInput.native_setter_js("#email", "test@test.com")
|
|
45
|
+
assert "HTMLInputElement" in js
|
|
46
|
+
assert "test@test.com" in js
|
|
47
|
+
assert "nativeInputValueSetter" in js
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def test_navigate_params():
|
|
51
|
+
params = CDPNavigation.navigate_params("https://example.com")
|
|
52
|
+
assert params["url"] == "https://example.com"
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def test_evaluate_params():
|
|
56
|
+
params = CDPNavigation.evaluate_params("document.title")
|
|
57
|
+
assert params["expression"] == "document.title"
|
|
58
|
+
assert params["returnByValue"] is True
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def test_screenshot_params():
|
|
62
|
+
params = CDPNavigation.screenshot_params("jpeg", 70)
|
|
63
|
+
assert params["format"] == "jpeg"
|
|
64
|
+
assert params["quality"] == 70
|