browser-toolkit 0.0.1a1__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.
- browser_toolkit/__init__.py +2 -0
- browser_toolkit/base_toolkit.py +584 -0
- browser_toolkit/camoufox.py +10 -0
- browser_toolkit/create_browser/__init__.py +0 -0
- browser_toolkit/create_browser/playwright.py +27 -0
- browser_toolkit/playwright.py +505 -0
- browser_toolkit/selenium.py +372 -0
- browser_toolkit/selenium_toolkit/__init__.py +1 -0
- browser_toolkit/selenium_toolkit/selenium_toolkit.py +408 -0
- browser_toolkit/selenium_toolkit/utils.py +10 -0
- browser_toolkit/types.py +49 -0
- browser_toolkit/utils.py +2 -0
- browser_toolkit-0.0.1a1.dist-info/METADATA +85 -0
- browser_toolkit-0.0.1a1.dist-info/RECORD +17 -0
- browser_toolkit-0.0.1a1.dist-info/WHEEL +5 -0
- browser_toolkit-0.0.1a1.dist-info/licenses/LICENSE +339 -0
- browser_toolkit-0.0.1a1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,584 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import functools
|
|
3
|
+
import inspect
|
|
4
|
+
from abc import ABC, abstractmethod
|
|
5
|
+
from datetime import datetime
|
|
6
|
+
from random import uniform
|
|
7
|
+
from typing import Self
|
|
8
|
+
|
|
9
|
+
from browser_toolkit.types import Cookie
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class BaseWebElement(ABC):
|
|
13
|
+
"""Base class for web elements"""
|
|
14
|
+
|
|
15
|
+
@abstractmethod
|
|
16
|
+
async def click(self, selector: str, delay: int = 0) -> None:
|
|
17
|
+
"""
|
|
18
|
+
Clicks the element
|
|
19
|
+
|
|
20
|
+
:param selector: string - CSS selector or XPath
|
|
21
|
+
:param delay: int - time to keep the mouse button pressed in seconds (default: 0)
|
|
22
|
+
:return:
|
|
23
|
+
"""
|
|
24
|
+
pass
|
|
25
|
+
|
|
26
|
+
@abstractmethod
|
|
27
|
+
async def click_js(self) -> None:
|
|
28
|
+
"""
|
|
29
|
+
Clicks the element using JavaScript
|
|
30
|
+
|
|
31
|
+
:return:
|
|
32
|
+
"""
|
|
33
|
+
pass
|
|
34
|
+
|
|
35
|
+
@abstractmethod
|
|
36
|
+
async def type(self, text: str, interval: float | int, clear_before: bool) -> None:
|
|
37
|
+
"""
|
|
38
|
+
Fills the element with the text
|
|
39
|
+
|
|
40
|
+
:param text: string - text to fill
|
|
41
|
+
:param interval: float or int - time to wait between each character in seconds
|
|
42
|
+
:param clear_before: bool - whether to clear the field before filling
|
|
43
|
+
:return:
|
|
44
|
+
"""
|
|
45
|
+
pass
|
|
46
|
+
|
|
47
|
+
@abstractmethod
|
|
48
|
+
async def clear(self) -> None:
|
|
49
|
+
"""
|
|
50
|
+
Clears the element
|
|
51
|
+
|
|
52
|
+
:return:
|
|
53
|
+
"""
|
|
54
|
+
pass
|
|
55
|
+
|
|
56
|
+
@abstractmethod
|
|
57
|
+
async def selector(self, selector: str) -> Self | None:
|
|
58
|
+
"""
|
|
59
|
+
Queries the web_element and returns the first element matching the selector.
|
|
60
|
+
:param selector:
|
|
61
|
+
:return:
|
|
62
|
+
"""
|
|
63
|
+
pass
|
|
64
|
+
|
|
65
|
+
@abstractmethod
|
|
66
|
+
async def selector_all(self, selector: str) -> list[Self]:
|
|
67
|
+
"""
|
|
68
|
+
Queries the web_element and returns all elements matching the selector.
|
|
69
|
+
:param selector:
|
|
70
|
+
:return:
|
|
71
|
+
"""
|
|
72
|
+
pass
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def now_str() -> str:
|
|
76
|
+
return datetime.now().strftime("%Y-%m-%dT%H-%M-%S")
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def main_decorator(func):
|
|
80
|
+
@functools.wraps(func)
|
|
81
|
+
async def wrapper(self: "BaseBrowserToolkit", *args, **kwargs):
|
|
82
|
+
has_screenshot = isinstance(self._screenshot_directory, str)
|
|
83
|
+
actions_names = [
|
|
84
|
+
# "goto",
|
|
85
|
+
"click",
|
|
86
|
+
"click_js",
|
|
87
|
+
"type",
|
|
88
|
+
"clear",
|
|
89
|
+
"scroll_to_element",
|
|
90
|
+
"scroll_to_top",
|
|
91
|
+
"scroll_to_bottom",
|
|
92
|
+
"reload",
|
|
93
|
+
"hard_reload",
|
|
94
|
+
]
|
|
95
|
+
func_name = func.__name__
|
|
96
|
+
|
|
97
|
+
# Ignore save_screenshot
|
|
98
|
+
if func_name == "save_screenshot":
|
|
99
|
+
return await func(self, *args, **kwargs)
|
|
100
|
+
|
|
101
|
+
# Waits a random time before executing the function
|
|
102
|
+
sleep_time = uniform(*self._wait_time_range)
|
|
103
|
+
if func_name in actions_names or func_name == "goto":
|
|
104
|
+
await asyncio.sleep(sleep_time)
|
|
105
|
+
|
|
106
|
+
# Takes screenshot before executing the function
|
|
107
|
+
if func_name in actions_names and has_screenshot:
|
|
108
|
+
file_path = f"{self._screenshot_directory}/{now_str()}_{func_name}.jpeg"
|
|
109
|
+
await self.save_screenshot(file_path=file_path)
|
|
110
|
+
|
|
111
|
+
# Executes the function and catches exceptions to take a screenshot if it fails
|
|
112
|
+
try:
|
|
113
|
+
return await func(self, *args, **kwargs)
|
|
114
|
+
except Exception as e:
|
|
115
|
+
if has_screenshot:
|
|
116
|
+
file_path = f"{self._screenshot_directory}/{now_str()}_exeption.jpeg"
|
|
117
|
+
await self.save_screenshot(file_path=file_path)
|
|
118
|
+
raise e
|
|
119
|
+
|
|
120
|
+
return wrapper
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
class AutoDecorate:
|
|
124
|
+
def __init_subclass__(cls, **kwargs):
|
|
125
|
+
super().__init_subclass__(**kwargs)
|
|
126
|
+
for attr_name, attr_value in cls.__dict__.items():
|
|
127
|
+
if inspect.iscoroutinefunction(attr_value):
|
|
128
|
+
setattr(cls, attr_name, main_decorator(attr_value))
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
class BaseBrowserToolkit(ABC, AutoDecorate):
|
|
132
|
+
_wait_time_range = (0, 0)
|
|
133
|
+
_screenshot_directory: str | None = None
|
|
134
|
+
|
|
135
|
+
# def __init__(self, browser):
|
|
136
|
+
# self.browser = browser
|
|
137
|
+
|
|
138
|
+
# --------------------------- START decorators ---------------------------
|
|
139
|
+
async def change_wait_time(self, range_time: tuple = (0, 0)):
|
|
140
|
+
first, last = range_time
|
|
141
|
+
|
|
142
|
+
if not (first >= 0 and last >= first):
|
|
143
|
+
raise ValueError(f"range_time must be a tuple with positive values")
|
|
144
|
+
|
|
145
|
+
self._wait_time_range = range_time
|
|
146
|
+
|
|
147
|
+
async def change_screenshot_directory(self, screenshot_directory: str):
|
|
148
|
+
self._screenshot_directory = screenshot_directory
|
|
149
|
+
|
|
150
|
+
# --------------------------- END decorators ---------------------------
|
|
151
|
+
|
|
152
|
+
# --------------------------- START session management ---------------------------
|
|
153
|
+
@abstractmethod
|
|
154
|
+
async def close(self) -> None:
|
|
155
|
+
"""
|
|
156
|
+
Closes the browser tab
|
|
157
|
+
:return:
|
|
158
|
+
"""
|
|
159
|
+
|
|
160
|
+
# --------------------------- END session management ---------------------------
|
|
161
|
+
|
|
162
|
+
# --------------------------- START selectors ---------------------------
|
|
163
|
+
@abstractmethod
|
|
164
|
+
async def selector(self, selector: str, web_element: BaseWebElement | None = None) -> BaseWebElement | None:
|
|
165
|
+
"""
|
|
166
|
+
Queries the page and returns the first element matching the selector.
|
|
167
|
+
If a web_element is provided, it queries within that element instead of the whole page.
|
|
168
|
+
:param selector:
|
|
169
|
+
:param web_element:
|
|
170
|
+
:return:
|
|
171
|
+
"""
|
|
172
|
+
pass
|
|
173
|
+
|
|
174
|
+
@abstractmethod
|
|
175
|
+
async def selector_all(self, selector: str, web_element: BaseWebElement | None = None) -> list[BaseWebElement]:
|
|
176
|
+
"""
|
|
177
|
+
Queries the page and returns all elements matching the selector.
|
|
178
|
+
If a web_element is provided, it queries within that element instead of the whole page.
|
|
179
|
+
:param selector:
|
|
180
|
+
:param web_element:
|
|
181
|
+
:return:
|
|
182
|
+
"""
|
|
183
|
+
pass
|
|
184
|
+
|
|
185
|
+
# --------------------------- END selectors ---------------------------
|
|
186
|
+
|
|
187
|
+
# --------------------------- START Actions ---------------------------
|
|
188
|
+
@abstractmethod
|
|
189
|
+
async def goto(self, url: str, timeout: int = 30) -> None:
|
|
190
|
+
"""
|
|
191
|
+
Navigates to URL
|
|
192
|
+
|
|
193
|
+
:param url: url to navigate to
|
|
194
|
+
:param timeout: maximum time to wait for the page to load in seconds
|
|
195
|
+
:return:
|
|
196
|
+
"""
|
|
197
|
+
|
|
198
|
+
pass
|
|
199
|
+
|
|
200
|
+
@abstractmethod
|
|
201
|
+
async def click(self, selector: str, delay: int = 0) -> None:
|
|
202
|
+
"""
|
|
203
|
+
Clicks the element matching the selector
|
|
204
|
+
|
|
205
|
+
:param selector: string - CSS selector or XPath
|
|
206
|
+
:param delay: int - time to keep the mouse button pressed in seconds (default: 0)
|
|
207
|
+
:return:
|
|
208
|
+
"""
|
|
209
|
+
pass
|
|
210
|
+
|
|
211
|
+
@abstractmethod
|
|
212
|
+
async def click_js(self, selector: str) -> None:
|
|
213
|
+
"""
|
|
214
|
+
Clicks the element matching the selector using JavaScript
|
|
215
|
+
|
|
216
|
+
:param selector: string - CSS selector or XPath
|
|
217
|
+
:return:
|
|
218
|
+
"""
|
|
219
|
+
pass
|
|
220
|
+
|
|
221
|
+
@abstractmethod
|
|
222
|
+
async def type(self, text: str, selector: str, interval: float | int, clear_before: bool) -> None:
|
|
223
|
+
"""
|
|
224
|
+
Fills the element matching the selector with the text
|
|
225
|
+
|
|
226
|
+
:param text: string - text to fill
|
|
227
|
+
:param selector: string - CSS selector or XPath
|
|
228
|
+
:param interval: float or int - time to wait between each character
|
|
229
|
+
:param clear_before: bool - whether to clear the field before filling
|
|
230
|
+
:return:
|
|
231
|
+
"""
|
|
232
|
+
pass
|
|
233
|
+
|
|
234
|
+
@abstractmethod
|
|
235
|
+
async def clear(self, selector: str) -> None:
|
|
236
|
+
"""
|
|
237
|
+
Clears the element matching the selector
|
|
238
|
+
|
|
239
|
+
:param selector: string - CSS selector or XPath
|
|
240
|
+
:return:
|
|
241
|
+
"""
|
|
242
|
+
pass
|
|
243
|
+
|
|
244
|
+
@abstractmethod
|
|
245
|
+
async def scroll_to_element(self, selector: str) -> None:
|
|
246
|
+
"""
|
|
247
|
+
Scrolls to the element matching the selector
|
|
248
|
+
|
|
249
|
+
:param selector: string - CSS selector or XPath
|
|
250
|
+
:return:
|
|
251
|
+
"""
|
|
252
|
+
pass
|
|
253
|
+
|
|
254
|
+
@abstractmethod
|
|
255
|
+
async def scroll_to_top(self) -> None:
|
|
256
|
+
"""
|
|
257
|
+
Scrolls to the top of the page
|
|
258
|
+
|
|
259
|
+
:return:
|
|
260
|
+
"""
|
|
261
|
+
pass
|
|
262
|
+
|
|
263
|
+
@abstractmethod
|
|
264
|
+
async def scroll_to_bottom(self) -> None:
|
|
265
|
+
"""
|
|
266
|
+
Scrolls to the bottom of the page
|
|
267
|
+
|
|
268
|
+
:return:
|
|
269
|
+
"""
|
|
270
|
+
pass
|
|
271
|
+
|
|
272
|
+
@abstractmethod
|
|
273
|
+
async def reload(self) -> None:
|
|
274
|
+
"""
|
|
275
|
+
Reloads the page
|
|
276
|
+
|
|
277
|
+
:return:
|
|
278
|
+
"""
|
|
279
|
+
pass
|
|
280
|
+
|
|
281
|
+
@abstractmethod
|
|
282
|
+
async def hard_reload(self) -> None:
|
|
283
|
+
"""
|
|
284
|
+
Hard reloads the page (ignoring cache)
|
|
285
|
+
|
|
286
|
+
:return:
|
|
287
|
+
"""
|
|
288
|
+
pass
|
|
289
|
+
|
|
290
|
+
# --------------------------- END Actions ---------------------------
|
|
291
|
+
|
|
292
|
+
# --------------------------- START page data ---------------------------
|
|
293
|
+
@property
|
|
294
|
+
@abstractmethod
|
|
295
|
+
async def current_url(self) -> str:
|
|
296
|
+
"""
|
|
297
|
+
Gets the current URL
|
|
298
|
+
|
|
299
|
+
:return: str - current URL
|
|
300
|
+
"""
|
|
301
|
+
pass
|
|
302
|
+
|
|
303
|
+
@property
|
|
304
|
+
@abstractmethod
|
|
305
|
+
async def title(self) -> str:
|
|
306
|
+
"""
|
|
307
|
+
Gets the page title
|
|
308
|
+
|
|
309
|
+
:return: str - page title
|
|
310
|
+
"""
|
|
311
|
+
pass
|
|
312
|
+
|
|
313
|
+
@property
|
|
314
|
+
@abstractmethod
|
|
315
|
+
async def page_source(self) -> str:
|
|
316
|
+
"""
|
|
317
|
+
Gets the page source
|
|
318
|
+
|
|
319
|
+
:return: str - page source
|
|
320
|
+
"""
|
|
321
|
+
pass
|
|
322
|
+
|
|
323
|
+
@abstractmethod
|
|
324
|
+
async def get_text(self, selector: str) -> str:
|
|
325
|
+
"""
|
|
326
|
+
Gets the text from the element matching the selector
|
|
327
|
+
|
|
328
|
+
:param selector: string - CSS selector or XPath
|
|
329
|
+
:return: str - text of the element
|
|
330
|
+
"""
|
|
331
|
+
|
|
332
|
+
@abstractmethod
|
|
333
|
+
async def get_attribute(self, selector: str, attribute: str) -> str:
|
|
334
|
+
"""
|
|
335
|
+
Gets the attribute from the element matching the selector
|
|
336
|
+
|
|
337
|
+
:param selector: string - CSS selector or XPath
|
|
338
|
+
:param attribute: string - attribute name
|
|
339
|
+
:return: str - attribute of the element
|
|
340
|
+
"""
|
|
341
|
+
pass
|
|
342
|
+
|
|
343
|
+
@abstractmethod
|
|
344
|
+
async def save_screenshot(self, file_path: str) -> None:
|
|
345
|
+
"""
|
|
346
|
+
Takes a screenshot of the current page and saves it to the exception directory if it is set
|
|
347
|
+
:param file_path:
|
|
348
|
+
:return:
|
|
349
|
+
"""
|
|
350
|
+
pass
|
|
351
|
+
|
|
352
|
+
# --------------------------- END page data ---------------------------
|
|
353
|
+
|
|
354
|
+
# --------------------------- START network ---------------------------
|
|
355
|
+
@abstractmethod
|
|
356
|
+
async def get_network_requests(self) -> list[dict]:
|
|
357
|
+
"""
|
|
358
|
+
Get all network Requests
|
|
359
|
+
:return:
|
|
360
|
+
"""
|
|
361
|
+
pass
|
|
362
|
+
|
|
363
|
+
@abstractmethod
|
|
364
|
+
async def get_network_response_body(self, request_id: str) -> str:
|
|
365
|
+
"""
|
|
366
|
+
Gets the response body of the network request with the given request ID
|
|
367
|
+
|
|
368
|
+
:param request_id: string - network request ID
|
|
369
|
+
:return: str - response body of the network request
|
|
370
|
+
"""
|
|
371
|
+
pass
|
|
372
|
+
|
|
373
|
+
# --------------------------- END network ---------------------------
|
|
374
|
+
|
|
375
|
+
# --------------------------- START scripts ---------------------------
|
|
376
|
+
@abstractmethod
|
|
377
|
+
async def execute_script(self, script: str) -> any:
|
|
378
|
+
"""
|
|
379
|
+
Executes the JavaScript script in the context of the current page
|
|
380
|
+
|
|
381
|
+
:param script: string - JavaScript code to execute
|
|
382
|
+
:return:
|
|
383
|
+
"""
|
|
384
|
+
pass
|
|
385
|
+
|
|
386
|
+
@abstractmethod
|
|
387
|
+
async def execute_cdp_cmd(self, cmd: str, params: dict) -> any:
|
|
388
|
+
"""
|
|
389
|
+
Executes the Chrome DevTools Protocol command in the context of the current page
|
|
390
|
+
|
|
391
|
+
:param cmd: string - CDP command to execute
|
|
392
|
+
:param params: dict - parameters for the CDP command
|
|
393
|
+
:return:
|
|
394
|
+
"""
|
|
395
|
+
pass
|
|
396
|
+
|
|
397
|
+
# --------------------------- END scripts ---------------------------
|
|
398
|
+
|
|
399
|
+
# --------------------------- START wait ---------------------------
|
|
400
|
+
@abstractmethod
|
|
401
|
+
async def element_is_present(self, selector: str, timeout: int) -> bool:
|
|
402
|
+
"""
|
|
403
|
+
Checks if the element matching the selector is present
|
|
404
|
+
|
|
405
|
+
:param selector: string - CSS selector or XPath
|
|
406
|
+
:param timeout: int - seconds to wait for the element
|
|
407
|
+
:return: bool - whether the element is present
|
|
408
|
+
"""
|
|
409
|
+
pass
|
|
410
|
+
|
|
411
|
+
@abstractmethod
|
|
412
|
+
async def element_is_visible(self, selector: str, timeout: int) -> bool:
|
|
413
|
+
"""
|
|
414
|
+
Checks if the element matching the selector is visible
|
|
415
|
+
|
|
416
|
+
:param selector: string - CSS selector or XPath
|
|
417
|
+
:param timeout: int - seconds to wait for the element
|
|
418
|
+
:return: bool - whether the element is visible
|
|
419
|
+
"""
|
|
420
|
+
pass
|
|
421
|
+
|
|
422
|
+
@abstractmethod
|
|
423
|
+
async def element_is_invisible(self, selector: str, timeout: int) -> bool:
|
|
424
|
+
"""
|
|
425
|
+
Checks if the element matching the selector is invisible
|
|
426
|
+
|
|
427
|
+
:param selector: string - CSS selector or XPath
|
|
428
|
+
:param timeout: int - seconds to wait for the element
|
|
429
|
+
:return: bool - whether the element is invisible
|
|
430
|
+
"""
|
|
431
|
+
pass
|
|
432
|
+
|
|
433
|
+
@abstractmethod
|
|
434
|
+
async def element_is_clickable(self, selector: str, timeout: int) -> bool:
|
|
435
|
+
"""
|
|
436
|
+
Checks if the element matching the selector is clickable
|
|
437
|
+
|
|
438
|
+
:param selector: string - CSS selector or XPath
|
|
439
|
+
:param timeout: int - seconds to wait for the element
|
|
440
|
+
:return: bool - whether the element is clickable
|
|
441
|
+
"""
|
|
442
|
+
pass
|
|
443
|
+
|
|
444
|
+
@abstractmethod
|
|
445
|
+
async def text_is_present(self, text: str, selector: str, timeout: int) -> bool:
|
|
446
|
+
"""
|
|
447
|
+
Checks if the text is present in the element matching the selector
|
|
448
|
+
|
|
449
|
+
:param text: string - text to check
|
|
450
|
+
:param selector: string - CSS selector or XPath
|
|
451
|
+
:param timeout: int - seconds to wait for the element
|
|
452
|
+
:return: bool - whether the text is present in the element
|
|
453
|
+
"""
|
|
454
|
+
pass
|
|
455
|
+
|
|
456
|
+
@abstractmethod
|
|
457
|
+
async def alert_is_present(self, timeout: int, message: str) -> bool:
|
|
458
|
+
"""
|
|
459
|
+
Checks if an alert is present
|
|
460
|
+
|
|
461
|
+
:param timeout: int - seconds to wait for the alert
|
|
462
|
+
:param message: str - alert message
|
|
463
|
+
:return: bool - whether an alert is present
|
|
464
|
+
"""
|
|
465
|
+
pass
|
|
466
|
+
|
|
467
|
+
@abstractmethod
|
|
468
|
+
async def page_is_loading(self, timeout: int) -> bool:
|
|
469
|
+
"""
|
|
470
|
+
Checks if the page is ready
|
|
471
|
+
|
|
472
|
+
:param timeout: int - seconds to wait for the page to be ready
|
|
473
|
+
:return: bool - whether the page is ready
|
|
474
|
+
"""
|
|
475
|
+
pass
|
|
476
|
+
|
|
477
|
+
# --------------------------- END wait ---------------------------
|
|
478
|
+
|
|
479
|
+
# --------------------------- START session data ---------------------------
|
|
480
|
+
@abstractmethod
|
|
481
|
+
async def get_all_cookies(self) -> list[Cookie]:
|
|
482
|
+
"""
|
|
483
|
+
Gets all cookies
|
|
484
|
+
:return: list[Cookie]
|
|
485
|
+
"""
|
|
486
|
+
pass
|
|
487
|
+
|
|
488
|
+
async def get_cookies_filter(
|
|
489
|
+
self, name: str | None = None, domain: str | None = None, path: str | None = None
|
|
490
|
+
) -> list[Cookie]:
|
|
491
|
+
"""
|
|
492
|
+
Gets cookies filtered by name, domain and path
|
|
493
|
+
:param name:
|
|
494
|
+
:param domain:
|
|
495
|
+
:param path:
|
|
496
|
+
:return:
|
|
497
|
+
"""
|
|
498
|
+
cookies = await self.get_all_cookies()
|
|
499
|
+
return [cookie for cookie in cookies if cookie.name == name]
|
|
500
|
+
|
|
501
|
+
async def get_cookie_by_name(self, name: str) -> Cookie | None:
|
|
502
|
+
"""
|
|
503
|
+
Gets a cookie by name
|
|
504
|
+
|
|
505
|
+
:param name: string - name of the cookie
|
|
506
|
+
:return: Cookie | None - cookie with the given name
|
|
507
|
+
"""
|
|
508
|
+
cookies = await self.get_all_cookies()
|
|
509
|
+
for cookie in cookies:
|
|
510
|
+
if cookie.name == name:
|
|
511
|
+
return cookie
|
|
512
|
+
return None
|
|
513
|
+
|
|
514
|
+
@abstractmethod
|
|
515
|
+
async def add_cookie(self, cookie: Cookie) -> None:
|
|
516
|
+
"""
|
|
517
|
+
Adds a cookie to the current session
|
|
518
|
+
|
|
519
|
+
:param cookie: Cookie - cookie to add
|
|
520
|
+
:return:
|
|
521
|
+
"""
|
|
522
|
+
pass
|
|
523
|
+
|
|
524
|
+
async def add_cookies(self, cookies: list[Cookie]) -> None:
|
|
525
|
+
"""
|
|
526
|
+
Adds multiple cookies to the current session
|
|
527
|
+
|
|
528
|
+
:param cookies: list[Cookie] - cookies to add
|
|
529
|
+
:return:
|
|
530
|
+
"""
|
|
531
|
+
for cookie in cookies:
|
|
532
|
+
await self.add_cookie(cookie)
|
|
533
|
+
|
|
534
|
+
@abstractmethod
|
|
535
|
+
async def delete_all_cookies(self) -> None:
|
|
536
|
+
"""
|
|
537
|
+
Deletes all cookies from the current session
|
|
538
|
+
:return:
|
|
539
|
+
"""
|
|
540
|
+
pass
|
|
541
|
+
|
|
542
|
+
@abstractmethod
|
|
543
|
+
async def delete_cookie_by_name(self, name: str) -> None:
|
|
544
|
+
"""
|
|
545
|
+
Deletes a cookie by name
|
|
546
|
+
|
|
547
|
+
:param name: string - name of the cookie to delete
|
|
548
|
+
:return:
|
|
549
|
+
"""
|
|
550
|
+
pass
|
|
551
|
+
|
|
552
|
+
@abstractmethod
|
|
553
|
+
async def delete_cookie_filter(
|
|
554
|
+
self, name: str | None = None, domain: str | None = None, path: str | None = None
|
|
555
|
+
) -> None:
|
|
556
|
+
"""
|
|
557
|
+
Deletes cookies by name, domain, and path
|
|
558
|
+
|
|
559
|
+
:param name:
|
|
560
|
+
:param domain:
|
|
561
|
+
:param path:
|
|
562
|
+
:return:
|
|
563
|
+
"""
|
|
564
|
+
pass
|
|
565
|
+
|
|
566
|
+
@abstractmethod
|
|
567
|
+
async def get_all_local_storage(self) -> dict:
|
|
568
|
+
"""
|
|
569
|
+
Gets all local storage
|
|
570
|
+
:return: dict
|
|
571
|
+
"""
|
|
572
|
+
pass
|
|
573
|
+
|
|
574
|
+
async def get_local_storage_filter(self, name: str) -> str | None:
|
|
575
|
+
"""
|
|
576
|
+
Gets a local storage item value by name
|
|
577
|
+
|
|
578
|
+
:param name:
|
|
579
|
+
:return:
|
|
580
|
+
"""
|
|
581
|
+
local_storage = await self.get_all_local_storage()
|
|
582
|
+
return local_storage.get(name, None)
|
|
583
|
+
|
|
584
|
+
# --------------------------- END session data ---------------------------
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from camoufox import AsyncCamoufox
|
|
2
|
+
from playwright.async_api import Page
|
|
3
|
+
|
|
4
|
+
from browser_toolkit.playwright import PlaywrightTollKit
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class CamoufoxTollKit(PlaywrightTollKit):
|
|
8
|
+
def __init__(self, browser: AsyncCamoufox, page: Page, *args, **kwargs):
|
|
9
|
+
self.browser: AsyncCamoufox = browser
|
|
10
|
+
self.page: Page = page
|
|
File without changes
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from playwright.async_api import async_playwright, Browser, Page
|
|
2
|
+
from browser_toolkit.playwright import PlaywrightTollKit
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
async def get_playwright(headless: bool = False) -> tuple[Browser, Page]:
|
|
6
|
+
playwright = await async_playwright().start()
|
|
7
|
+
browser = await playwright.chromium.launch(headless=headless)
|
|
8
|
+
page = await browser.new_page()
|
|
9
|
+
return browser, page
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
async def get_playwright_toolkit() -> PlaywrightTollKit:
|
|
13
|
+
browser, page = await get_playwright()
|
|
14
|
+
btk = PlaywrightTollKit(
|
|
15
|
+
browser=browser,
|
|
16
|
+
page=page,
|
|
17
|
+
)
|
|
18
|
+
return btk
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
async def main():
|
|
22
|
+
async with async_playwright() as p:
|
|
23
|
+
browser = await p.chromium.launch()
|
|
24
|
+
page = await browser.new_page()
|
|
25
|
+
await page.goto("https://playwright.dev")
|
|
26
|
+
print(await page.title())
|
|
27
|
+
await browser.close()
|