cdp-toolkit 1.0.0__py3-none-any.whl
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.
- __init__.py +0 -0
- cdp_client.py +144 -0
- cdp_toolkit-1.0.0.dist-info/METADATA +52 -0
- cdp_toolkit-1.0.0.dist-info/RECORD +6 -0
- cdp_toolkit-1.0.0.dist-info/WHEEL +5 -0
- cdp_toolkit-1.0.0.dist-info/top_level.txt +2 -0
__init__.py
ADDED
|
File without changes
|
cdp_client.py
ADDED
|
@@ -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.0.0
|
|
4
|
+
Summary: Chrome DevTools Protocol automation toolkit
|
|
5
|
+
Author: AMEOBIUS
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/AMEOBIUS/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,6 @@
|
|
|
1
|
+
__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
cdp_client.py,sha256=njuP-5H5V0R9blrxbr5urcLeqkKHHwWAUsdLatGoOSY,4649
|
|
3
|
+
cdp_toolkit-1.0.0.dist-info/METADATA,sha256=t3ruTcNNIPJsgrHDIyi6TrV5bjGjm1-XE-lFFNo7DJo,1207
|
|
4
|
+
cdp_toolkit-1.0.0.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
|
|
5
|
+
cdp_toolkit-1.0.0.dist-info/top_level.txt,sha256=fghO1ikkAu__8HV4TonY4g3uTQpjfLzp2IuX_kXHV1s,20
|
|
6
|
+
cdp_toolkit-1.0.0.dist-info/RECORD,,
|