cdpwave 0.1.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.
- cdpwave/__init__.py +34 -0
- cdpwave/browser/__init__.py +0 -0
- cdpwave/browser/discovery.py +86 -0
- cdpwave/browser/finder.py +130 -0
- cdpwave/browser/launcher.py +170 -0
- cdpwave/client.py +332 -0
- cdpwave/domains/__init__.py +0 -0
- cdpwave/domains/base.py +15 -0
- cdpwave/domains/console.py +14 -0
- cdpwave/domains/dom.py +92 -0
- cdpwave/domains/log.py +26 -0
- cdpwave/domains/network.py +141 -0
- cdpwave/domains/page.py +86 -0
- cdpwave/domains/runtime.py +71 -0
- cdpwave/domains/target.py +40 -0
- cdpwave/events/__init__.py +0 -0
- cdpwave/events/dispatcher.py +44 -0
- cdpwave/events/handlers.py +37 -0
- cdpwave/exceptions.py +40 -0
- cdpwave/session/__init__.py +0 -0
- cdpwave/session/manager.py +32 -0
- cdpwave/transport/__init__.py +0 -0
- cdpwave/transport/connection.py +142 -0
- cdpwave/transport/correlation.py +37 -0
- cdpwave/transport/serializer.py +33 -0
- cdpwave/types.py +8 -0
- cdpwave-0.1.0.dist-info/METADATA +94 -0
- cdpwave-0.1.0.dist-info/RECORD +30 -0
- cdpwave-0.1.0.dist-info/WHEEL +4 -0
- cdpwave-0.1.0.dist-info/licenses/LICENSE +21 -0
cdpwave/client.py
ADDED
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import contextlib
|
|
4
|
+
import logging
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from cdpwave.browser.discovery import TargetDiscovery, TargetInfo
|
|
8
|
+
from cdpwave.browser.launcher import BrowserLauncher
|
|
9
|
+
from cdpwave.domains.console import ConsoleDomain
|
|
10
|
+
from cdpwave.domains.dom import DOMDomain
|
|
11
|
+
from cdpwave.domains.log import LogDomain
|
|
12
|
+
from cdpwave.domains.network import NetworkDomain
|
|
13
|
+
from cdpwave.domains.page import PageDomain
|
|
14
|
+
from cdpwave.domains.runtime import RuntimeDomain
|
|
15
|
+
from cdpwave.domains.target import TargetDomain
|
|
16
|
+
from cdpwave.events.dispatcher import EventDispatcher
|
|
17
|
+
from cdpwave.events.handlers import EventHandler, Subscription
|
|
18
|
+
from cdpwave.exceptions import SessionClosedError
|
|
19
|
+
from cdpwave.session.manager import SessionManager
|
|
20
|
+
from cdpwave.transport.connection import Connection
|
|
21
|
+
from cdpwave.types import CommandSender
|
|
22
|
+
|
|
23
|
+
logger = logging.getLogger("cdpwave.client")
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class CDPSession:
|
|
27
|
+
def __init__(
|
|
28
|
+
self,
|
|
29
|
+
connection: Connection,
|
|
30
|
+
session_id: str,
|
|
31
|
+
target_id: str,
|
|
32
|
+
client: CDPClient | None = None,
|
|
33
|
+
) -> None:
|
|
34
|
+
self._connection = connection
|
|
35
|
+
self._session_id = session_id
|
|
36
|
+
self._target_id = target_id
|
|
37
|
+
self._closed = False
|
|
38
|
+
self._dispatcher = EventDispatcher()
|
|
39
|
+
|
|
40
|
+
if client is not None:
|
|
41
|
+
client._session_dispatchers[session_id] = self._dispatcher
|
|
42
|
+
self._client = client
|
|
43
|
+
|
|
44
|
+
async def _send(
|
|
45
|
+
method: str,
|
|
46
|
+
params: dict[str, Any] | None = None,
|
|
47
|
+
) -> dict[str, Any]:
|
|
48
|
+
return await connection.send_command(
|
|
49
|
+
method,
|
|
50
|
+
params,
|
|
51
|
+
session_id=session_id,
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
self._sender: CommandSender = _send
|
|
55
|
+
self._page = PageDomain(self._sender)
|
|
56
|
+
self._runtime = RuntimeDomain(self._sender)
|
|
57
|
+
self._target = TargetDomain(self._sender)
|
|
58
|
+
self._network = NetworkDomain(self._sender)
|
|
59
|
+
self._dom = DOMDomain(self._sender)
|
|
60
|
+
self._log = LogDomain(self._sender)
|
|
61
|
+
self._console = ConsoleDomain(self._sender)
|
|
62
|
+
|
|
63
|
+
@property
|
|
64
|
+
def page(self) -> PageDomain:
|
|
65
|
+
return self._page
|
|
66
|
+
|
|
67
|
+
@property
|
|
68
|
+
def runtime(self) -> RuntimeDomain:
|
|
69
|
+
return self._runtime
|
|
70
|
+
|
|
71
|
+
@property
|
|
72
|
+
def target(self) -> TargetDomain:
|
|
73
|
+
return self._target
|
|
74
|
+
|
|
75
|
+
@property
|
|
76
|
+
def network(self) -> NetworkDomain:
|
|
77
|
+
return self._network
|
|
78
|
+
|
|
79
|
+
@property
|
|
80
|
+
def dom(self) -> DOMDomain:
|
|
81
|
+
return self._dom
|
|
82
|
+
|
|
83
|
+
@property
|
|
84
|
+
def log(self) -> LogDomain:
|
|
85
|
+
return self._log
|
|
86
|
+
|
|
87
|
+
@property
|
|
88
|
+
def console(self) -> ConsoleDomain:
|
|
89
|
+
return self._console
|
|
90
|
+
|
|
91
|
+
@property
|
|
92
|
+
def session_id(self) -> str:
|
|
93
|
+
return self._session_id
|
|
94
|
+
|
|
95
|
+
@property
|
|
96
|
+
def target_id(self) -> str:
|
|
97
|
+
return self._target_id
|
|
98
|
+
|
|
99
|
+
@property
|
|
100
|
+
def is_closed(self) -> bool:
|
|
101
|
+
return self._closed
|
|
102
|
+
|
|
103
|
+
async def send(
|
|
104
|
+
self,
|
|
105
|
+
method: str,
|
|
106
|
+
params: dict[str, Any] | None = None,
|
|
107
|
+
) -> dict[str, Any]:
|
|
108
|
+
if self._closed:
|
|
109
|
+
raise SessionClosedError(
|
|
110
|
+
f"Session {self._session_id} is closed"
|
|
111
|
+
)
|
|
112
|
+
return await self._sender(method, params)
|
|
113
|
+
|
|
114
|
+
async def close(self) -> None:
|
|
115
|
+
if self._closed:
|
|
116
|
+
return
|
|
117
|
+
self._closed = True
|
|
118
|
+
self._dispatcher.clear()
|
|
119
|
+
if self._client is not None:
|
|
120
|
+
self._client._session_dispatchers.pop(self._session_id, None)
|
|
121
|
+
with contextlib.suppress(Exception):
|
|
122
|
+
await self._connection.send_command(
|
|
123
|
+
"Target.detachFromTarget",
|
|
124
|
+
{"sessionId": self._session_id},
|
|
125
|
+
)
|
|
126
|
+
logger.info("Session %s closed", self._session_id)
|
|
127
|
+
|
|
128
|
+
def on(self, event_name: str, handler: EventHandler) -> Subscription:
|
|
129
|
+
return self._dispatcher.on(event_name, handler)
|
|
130
|
+
|
|
131
|
+
def off(self, event_name: str, handler: EventHandler) -> None:
|
|
132
|
+
self._dispatcher.off(event_name, handler)
|
|
133
|
+
|
|
134
|
+
async def __aenter__(self) -> CDPSession:
|
|
135
|
+
return self
|
|
136
|
+
|
|
137
|
+
async def __aexit__(
|
|
138
|
+
self,
|
|
139
|
+
exc_type: object,
|
|
140
|
+
exc_val: object,
|
|
141
|
+
exc_tb: object,
|
|
142
|
+
) -> None:
|
|
143
|
+
await self.close()
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
class CDPClient:
|
|
147
|
+
def __init__(
|
|
148
|
+
self,
|
|
149
|
+
connection: Connection,
|
|
150
|
+
launcher: BrowserLauncher | None = None,
|
|
151
|
+
discovery: TargetDiscovery | None = None,
|
|
152
|
+
) -> None:
|
|
153
|
+
self._connection = connection
|
|
154
|
+
self._launcher = launcher
|
|
155
|
+
self._discovery = discovery
|
|
156
|
+
self._session_manager = SessionManager(connection)
|
|
157
|
+
self._dispatcher = EventDispatcher()
|
|
158
|
+
self._session_dispatchers: dict[str, EventDispatcher] = {}
|
|
159
|
+
self._sessions: dict[str, CDPSession] = {}
|
|
160
|
+
self._closed = False
|
|
161
|
+
|
|
162
|
+
async def _event_callback(
|
|
163
|
+
self,
|
|
164
|
+
event_name: str,
|
|
165
|
+
params: dict[str, Any],
|
|
166
|
+
session_id: str | None,
|
|
167
|
+
) -> None:
|
|
168
|
+
if event_name == "Target.detachedFromTarget":
|
|
169
|
+
detached_session_id = params.get("sessionId")
|
|
170
|
+
if detached_session_id is not None:
|
|
171
|
+
session = self._sessions.get(detached_session_id)
|
|
172
|
+
if session is not None:
|
|
173
|
+
session._closed = True
|
|
174
|
+
session._dispatcher.clear()
|
|
175
|
+
self._session_dispatchers.pop(detached_session_id, None)
|
|
176
|
+
self._sessions.pop(detached_session_id, None)
|
|
177
|
+
logger.info(
|
|
178
|
+
"Session %s detached by browser",
|
|
179
|
+
detached_session_id,
|
|
180
|
+
)
|
|
181
|
+
else:
|
|
182
|
+
logger.warning(
|
|
183
|
+
"Target.detachedFromTarget for unknown session %s",
|
|
184
|
+
detached_session_id,
|
|
185
|
+
)
|
|
186
|
+
return
|
|
187
|
+
|
|
188
|
+
if session_id is None:
|
|
189
|
+
await self._dispatcher.dispatch(event_name, params)
|
|
190
|
+
else:
|
|
191
|
+
dispatcher = self._session_dispatchers.get(session_id)
|
|
192
|
+
if dispatcher is not None:
|
|
193
|
+
await dispatcher.dispatch(event_name, params)
|
|
194
|
+
else:
|
|
195
|
+
logger.warning(
|
|
196
|
+
"Event %s for unknown session %s",
|
|
197
|
+
event_name,
|
|
198
|
+
session_id,
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
def on(self, event_name: str, handler: EventHandler) -> Subscription:
|
|
202
|
+
return self._dispatcher.on(event_name, handler)
|
|
203
|
+
|
|
204
|
+
def off(self, event_name: str, handler: EventHandler) -> None:
|
|
205
|
+
self._dispatcher.off(event_name, handler)
|
|
206
|
+
|
|
207
|
+
@classmethod
|
|
208
|
+
async def launch(
|
|
209
|
+
cls,
|
|
210
|
+
headless: bool = True,
|
|
211
|
+
browser_path: str | None = None,
|
|
212
|
+
port: int = 0,
|
|
213
|
+
user_data_dir: str | None = None,
|
|
214
|
+
extra_args: list[str] | None = None,
|
|
215
|
+
timeout: float = 10.0,
|
|
216
|
+
) -> CDPClient:
|
|
217
|
+
launcher = BrowserLauncher(
|
|
218
|
+
browser_path=browser_path,
|
|
219
|
+
port=port,
|
|
220
|
+
headless=headless,
|
|
221
|
+
user_data_dir=user_data_dir,
|
|
222
|
+
extra_args=extra_args,
|
|
223
|
+
)
|
|
224
|
+
info = await launcher.launch(timeout=timeout)
|
|
225
|
+
discovery = TargetDiscovery(port=info.port)
|
|
226
|
+
client = cls.__new__(cls)
|
|
227
|
+
client._connection = Connection(
|
|
228
|
+
info.web_socket_debugger_url,
|
|
229
|
+
event_callback=client._event_callback,
|
|
230
|
+
)
|
|
231
|
+
await client._connection.connect()
|
|
232
|
+
client._launcher = launcher
|
|
233
|
+
client._discovery = discovery
|
|
234
|
+
client._session_manager = SessionManager(client._connection)
|
|
235
|
+
client._dispatcher = EventDispatcher()
|
|
236
|
+
client._session_dispatchers = {}
|
|
237
|
+
client._sessions = {}
|
|
238
|
+
client._closed = False
|
|
239
|
+
return client
|
|
240
|
+
|
|
241
|
+
@classmethod
|
|
242
|
+
async def connect(
|
|
243
|
+
cls,
|
|
244
|
+
host: str = "localhost",
|
|
245
|
+
port: int = 9222,
|
|
246
|
+
) -> CDPClient:
|
|
247
|
+
discovery = TargetDiscovery(host=host, port=port)
|
|
248
|
+
version = await discovery.get_version()
|
|
249
|
+
client = cls.__new__(cls)
|
|
250
|
+
client._connection = Connection(
|
|
251
|
+
version.web_socket_debugger_url,
|
|
252
|
+
event_callback=client._event_callback,
|
|
253
|
+
)
|
|
254
|
+
await client._connection.connect()
|
|
255
|
+
client._launcher = None
|
|
256
|
+
client._discovery = discovery
|
|
257
|
+
client._session_manager = SessionManager(client._connection)
|
|
258
|
+
client._dispatcher = EventDispatcher()
|
|
259
|
+
client._session_dispatchers = {}
|
|
260
|
+
client._sessions = {}
|
|
261
|
+
client._closed = False
|
|
262
|
+
return client
|
|
263
|
+
|
|
264
|
+
async def new_page(self, url: str = "about:blank") -> CDPSession:
|
|
265
|
+
target_id = await self._session_manager.create_target(url)
|
|
266
|
+
session_id = await self._session_manager.attach_to_target(target_id)
|
|
267
|
+
session = CDPSession(
|
|
268
|
+
connection=self._connection,
|
|
269
|
+
session_id=session_id,
|
|
270
|
+
target_id=target_id,
|
|
271
|
+
client=self,
|
|
272
|
+
)
|
|
273
|
+
self._sessions[session_id] = session
|
|
274
|
+
return session
|
|
275
|
+
|
|
276
|
+
async def get_pages(self) -> list[TargetInfo]:
|
|
277
|
+
if self._discovery is None:
|
|
278
|
+
raise RuntimeError("Discovery is not available")
|
|
279
|
+
targets = await self._discovery.list_targets()
|
|
280
|
+
return [t for t in targets if t.type == "page"]
|
|
281
|
+
|
|
282
|
+
async def connect_to_page(self, target_id: str) -> CDPSession:
|
|
283
|
+
session_id = await self._session_manager.attach_to_target(target_id)
|
|
284
|
+
session = CDPSession(
|
|
285
|
+
connection=self._connection,
|
|
286
|
+
session_id=session_id,
|
|
287
|
+
target_id=target_id,
|
|
288
|
+
client=self,
|
|
289
|
+
)
|
|
290
|
+
self._sessions[session_id] = session
|
|
291
|
+
return session
|
|
292
|
+
|
|
293
|
+
async def close(self) -> None:
|
|
294
|
+
if self._closed:
|
|
295
|
+
return
|
|
296
|
+
self._closed = True
|
|
297
|
+
|
|
298
|
+
for session in list(self._sessions.values()):
|
|
299
|
+
with contextlib.suppress(Exception):
|
|
300
|
+
session._closed = True
|
|
301
|
+
session._dispatcher.clear()
|
|
302
|
+
self._session_dispatchers.pop(session._session_id, None)
|
|
303
|
+
self._sessions.clear()
|
|
304
|
+
self._dispatcher.clear()
|
|
305
|
+
|
|
306
|
+
with contextlib.suppress(Exception):
|
|
307
|
+
await self._connection.close()
|
|
308
|
+
|
|
309
|
+
if self._launcher is not None:
|
|
310
|
+
with contextlib.suppress(Exception):
|
|
311
|
+
await self._launcher.close()
|
|
312
|
+
|
|
313
|
+
logger.info("CDPClient closed")
|
|
314
|
+
|
|
315
|
+
@property
|
|
316
|
+
def is_closed(self) -> bool:
|
|
317
|
+
return self._closed or self._connection.is_closed
|
|
318
|
+
|
|
319
|
+
@property
|
|
320
|
+
def is_connected(self) -> bool:
|
|
321
|
+
return not self._connection.is_closed
|
|
322
|
+
|
|
323
|
+
async def __aenter__(self) -> CDPClient:
|
|
324
|
+
return self
|
|
325
|
+
|
|
326
|
+
async def __aexit__(
|
|
327
|
+
self,
|
|
328
|
+
exc_type: object,
|
|
329
|
+
exc_val: object,
|
|
330
|
+
exc_tb: object,
|
|
331
|
+
) -> None:
|
|
332
|
+
await self.close()
|
|
File without changes
|
cdpwave/domains/base.py
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
from cdpwave.types import CommandSender
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class BaseDomain:
|
|
7
|
+
def __init__(self, send: CommandSender) -> None:
|
|
8
|
+
self._send = send
|
|
9
|
+
|
|
10
|
+
async def _call(
|
|
11
|
+
self,
|
|
12
|
+
method: str,
|
|
13
|
+
params: dict[str, Any] | None = None,
|
|
14
|
+
) -> dict[str, Any]:
|
|
15
|
+
return await self._send(method, params)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
from cdpwave.domains.base import BaseDomain
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ConsoleDomain(BaseDomain):
|
|
7
|
+
async def enable(self) -> dict[str, Any]:
|
|
8
|
+
return await self._call("Console.enable")
|
|
9
|
+
|
|
10
|
+
async def disable(self) -> dict[str, Any]:
|
|
11
|
+
return await self._call("Console.disable")
|
|
12
|
+
|
|
13
|
+
async def clear_messages(self) -> dict[str, Any]:
|
|
14
|
+
return await self._call("Console.clearMessages")
|
cdpwave/domains/dom.py
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
from cdpwave.domains.base import BaseDomain
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class DOMDomain(BaseDomain):
|
|
7
|
+
async def enable(self) -> dict[str, Any]:
|
|
8
|
+
return await self._call("DOM.enable")
|
|
9
|
+
|
|
10
|
+
async def disable(self) -> dict[str, Any]:
|
|
11
|
+
return await self._call("DOM.disable")
|
|
12
|
+
|
|
13
|
+
async def get_document(
|
|
14
|
+
self,
|
|
15
|
+
depth: int = -1,
|
|
16
|
+
pierce: bool = False,
|
|
17
|
+
) -> dict[str, Any]:
|
|
18
|
+
return await self._call(
|
|
19
|
+
"DOM.getDocument",
|
|
20
|
+
{"depth": depth, "pierce": pierce},
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
async def get_outer_html(self, node_id: int) -> dict[str, Any]:
|
|
24
|
+
return await self._call(
|
|
25
|
+
"DOM.getOuterHTML",
|
|
26
|
+
{"nodeId": node_id},
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
async def get_inner_html(self, node_id: int) -> dict[str, Any]:
|
|
30
|
+
return await self._call(
|
|
31
|
+
"DOM.getInnerHTML",
|
|
32
|
+
{"nodeId": node_id},
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
async def query_selector(
|
|
36
|
+
self,
|
|
37
|
+
node_id: int,
|
|
38
|
+
selector: str,
|
|
39
|
+
) -> dict[str, Any]:
|
|
40
|
+
return await self._call(
|
|
41
|
+
"DOM.querySelector",
|
|
42
|
+
{"nodeId": node_id, "selector": selector},
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
async def query_selector_all(
|
|
46
|
+
self,
|
|
47
|
+
node_id: int,
|
|
48
|
+
selector: str,
|
|
49
|
+
) -> dict[str, Any]:
|
|
50
|
+
return await self._call(
|
|
51
|
+
"DOM.querySelectorAll",
|
|
52
|
+
{"nodeId": node_id, "selector": selector},
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
async def remove_node(self, node_id: int) -> dict[str, Any]:
|
|
56
|
+
return await self._call(
|
|
57
|
+
"DOM.removeNode",
|
|
58
|
+
{"nodeId": node_id},
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
async def set_attribute_value(
|
|
62
|
+
self,
|
|
63
|
+
node_id: int,
|
|
64
|
+
name: str,
|
|
65
|
+
value: str,
|
|
66
|
+
) -> dict[str, Any]:
|
|
67
|
+
return await self._call(
|
|
68
|
+
"DOM.setAttributeValue",
|
|
69
|
+
{"nodeId": node_id, "name": name, "value": value},
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
async def get_attribute(
|
|
73
|
+
self,
|
|
74
|
+
node_id: int,
|
|
75
|
+
name: str,
|
|
76
|
+
) -> dict[str, Any]:
|
|
77
|
+
return await self._call(
|
|
78
|
+
"DOM.getAttributes",
|
|
79
|
+
{"nodeId": node_id},
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
async def focus(self, node_id: int) -> dict[str, Any]:
|
|
83
|
+
return await self._call(
|
|
84
|
+
"DOM.focus",
|
|
85
|
+
{"nodeId": node_id},
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
async def scroll_into_view_if_needed(self, node_id: int) -> dict[str, Any]:
|
|
89
|
+
return await self._call(
|
|
90
|
+
"DOM.scrollIntoViewIfNeeded",
|
|
91
|
+
{"nodeId": node_id},
|
|
92
|
+
)
|
cdpwave/domains/log.py
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
from cdpwave.domains.base import BaseDomain
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class LogDomain(BaseDomain):
|
|
7
|
+
async def enable(self) -> dict[str, Any]:
|
|
8
|
+
return await self._call("Log.enable")
|
|
9
|
+
|
|
10
|
+
async def disable(self) -> dict[str, Any]:
|
|
11
|
+
return await self._call("Log.disable")
|
|
12
|
+
|
|
13
|
+
async def clear(self) -> dict[str, Any]:
|
|
14
|
+
return await self._call("Log.clear")
|
|
15
|
+
|
|
16
|
+
async def start_violation_report(
|
|
17
|
+
self,
|
|
18
|
+
config: list[dict[str, Any]],
|
|
19
|
+
) -> dict[str, Any]:
|
|
20
|
+
return await self._call(
|
|
21
|
+
"Log.startViolationsReport",
|
|
22
|
+
{"config": config},
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
async def stop_violation_report(self) -> dict[str, Any]:
|
|
26
|
+
return await self._call("Log.stopViolationsReport")
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
from cdpwave.domains.base import BaseDomain
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class NetworkDomain(BaseDomain):
|
|
7
|
+
async def enable(
|
|
8
|
+
self,
|
|
9
|
+
max_total_buffer_size: int | None = None,
|
|
10
|
+
max_resource_buffer_size: int | None = None,
|
|
11
|
+
max_post_data_size: int | None = None,
|
|
12
|
+
) -> dict[str, Any]:
|
|
13
|
+
params: dict[str, Any] = {}
|
|
14
|
+
if max_total_buffer_size is not None:
|
|
15
|
+
params["maxTotalBufferSize"] = max_total_buffer_size
|
|
16
|
+
if max_resource_buffer_size is not None:
|
|
17
|
+
params["maxResourceBufferSize"] = max_resource_buffer_size
|
|
18
|
+
if max_post_data_size is not None:
|
|
19
|
+
params["maxPostDataSize"] = max_post_data_size
|
|
20
|
+
return await self._call("Network.enable", params or None)
|
|
21
|
+
|
|
22
|
+
async def disable(self) -> dict[str, Any]:
|
|
23
|
+
return await self._call("Network.disable")
|
|
24
|
+
|
|
25
|
+
async def set_user_agent_override(
|
|
26
|
+
self,
|
|
27
|
+
user_agent: str,
|
|
28
|
+
accept_language: str | None = None,
|
|
29
|
+
platform: str | None = None,
|
|
30
|
+
) -> dict[str, Any]:
|
|
31
|
+
params: dict[str, Any] = {"userAgent": user_agent}
|
|
32
|
+
if accept_language is not None:
|
|
33
|
+
params["acceptLanguage"] = accept_language
|
|
34
|
+
if platform is not None:
|
|
35
|
+
params["platform"] = platform
|
|
36
|
+
return await self._call("Network.setUserAgentOverride", params)
|
|
37
|
+
|
|
38
|
+
async def set_extra_request_headers(
|
|
39
|
+
self,
|
|
40
|
+
headers: dict[str, str],
|
|
41
|
+
) -> dict[str, Any]:
|
|
42
|
+
return await self._call(
|
|
43
|
+
"Network.setExtraRequestHeaders",
|
|
44
|
+
{"headers": headers},
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
async def clear_browser_cookies(self) -> dict[str, Any]:
|
|
48
|
+
return await self._call("Network.clearBrowserCookies")
|
|
49
|
+
|
|
50
|
+
async def clear_browser_cache(self) -> dict[str, Any]:
|
|
51
|
+
return await self._call("Network.clearBrowserCache")
|
|
52
|
+
|
|
53
|
+
async def get_cookies(
|
|
54
|
+
self,
|
|
55
|
+
urls: list[str] | None = None,
|
|
56
|
+
) -> dict[str, Any]:
|
|
57
|
+
params: dict[str, Any] = {}
|
|
58
|
+
if urls is not None:
|
|
59
|
+
params["urls"] = urls
|
|
60
|
+
return await self._call("Network.getCookies", params or None)
|
|
61
|
+
|
|
62
|
+
async def set_cookie(
|
|
63
|
+
self,
|
|
64
|
+
name: str,
|
|
65
|
+
value: str,
|
|
66
|
+
url: str | None = None,
|
|
67
|
+
domain: str | None = None,
|
|
68
|
+
path: str | None = None,
|
|
69
|
+
secure: bool = False,
|
|
70
|
+
http_only: bool = False,
|
|
71
|
+
same_site: str | None = None,
|
|
72
|
+
expires: float | None = None,
|
|
73
|
+
) -> dict[str, Any]:
|
|
74
|
+
params: dict[str, Any] = {
|
|
75
|
+
"name": name,
|
|
76
|
+
"value": value,
|
|
77
|
+
"secure": secure,
|
|
78
|
+
"httpOnly": http_only,
|
|
79
|
+
}
|
|
80
|
+
if url is not None:
|
|
81
|
+
params["url"] = url
|
|
82
|
+
if domain is not None:
|
|
83
|
+
params["domain"] = domain
|
|
84
|
+
if path is not None:
|
|
85
|
+
params["path"] = path
|
|
86
|
+
if same_site is not None:
|
|
87
|
+
params["sameSite"] = same_site
|
|
88
|
+
if expires is not None:
|
|
89
|
+
params["expires"] = expires
|
|
90
|
+
return await self._call("Network.setCookie", params)
|
|
91
|
+
|
|
92
|
+
async def delete_cookies(
|
|
93
|
+
self,
|
|
94
|
+
name: str,
|
|
95
|
+
url: str | None = None,
|
|
96
|
+
domain: str | None = None,
|
|
97
|
+
path: str | None = None,
|
|
98
|
+
) -> dict[str, Any]:
|
|
99
|
+
params: dict[str, Any] = {"name": name}
|
|
100
|
+
if url is not None:
|
|
101
|
+
params["url"] = url
|
|
102
|
+
if domain is not None:
|
|
103
|
+
params["domain"] = domain
|
|
104
|
+
if path is not None:
|
|
105
|
+
params["path"] = path
|
|
106
|
+
return await self._call("Network.deleteCookies", params)
|
|
107
|
+
|
|
108
|
+
async def get_response_body(
|
|
109
|
+
self,
|
|
110
|
+
request_id: str,
|
|
111
|
+
) -> dict[str, Any]:
|
|
112
|
+
return await self._call(
|
|
113
|
+
"Network.getResponseBody",
|
|
114
|
+
{"requestId": request_id},
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
async def set_cache_disabled(
|
|
118
|
+
self,
|
|
119
|
+
cache_disabled: bool,
|
|
120
|
+
) -> dict[str, Any]:
|
|
121
|
+
return await self._call(
|
|
122
|
+
"Network.setCacheDisabled",
|
|
123
|
+
{"cacheDisabled": cache_disabled},
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
async def emulate_network_conditions(
|
|
127
|
+
self,
|
|
128
|
+
offline: bool = False,
|
|
129
|
+
latency: int = 0,
|
|
130
|
+
download_throughput: float = -1,
|
|
131
|
+
upload_throughput: float = -1,
|
|
132
|
+
) -> dict[str, Any]:
|
|
133
|
+
return await self._call(
|
|
134
|
+
"Network.emulateNetworkConditions",
|
|
135
|
+
{
|
|
136
|
+
"offline": offline,
|
|
137
|
+
"latency": latency,
|
|
138
|
+
"downloadThroughput": download_throughput,
|
|
139
|
+
"uploadThroughput": upload_throughput,
|
|
140
|
+
},
|
|
141
|
+
)
|