seleniumUts 1.1.1__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.
@@ -0,0 +1,697 @@
1
+ from seleniumUts.custom_driver import CustomChromeDriver, CustomRemoteDriver
2
+ from selenium.webdriver.support import expected_conditions as EC
3
+ from selenium.webdriver.support.ui import WebDriverWait
4
+ from selenium.webdriver.chrome.service import Service
5
+ from selenium.webdriver.common.by import By
6
+ import undetected_chromedriver as uc
7
+ from selenium import webdriver
8
+ from time import time, sleep
9
+ from pathlib import Path
10
+ from glob import glob
11
+ import base64
12
+
13
+ CAPABILITIES = {
14
+ "browserName": "chrome",
15
+ "version": "110.0",
16
+ "name": "default",
17
+ "enableVNC": True,
18
+ "enableVideo": False,
19
+ "sessionTimeout": "30m",
20
+ }
21
+
22
+ DEFAULT_OPTIONS = [
23
+ # "--disable-web-security",
24
+ "--verbose",
25
+ # "--no-sandbox",
26
+ "--disable-infobars",
27
+ "--disable-extensions",
28
+ "--disable-notifications",
29
+ "--disable-dev-shm-usage",
30
+ "--force-device-scale-factor=0.67",
31
+ "--disable-gpu",
32
+ "--start-maximized",
33
+ "--kiosk-printing",
34
+ "--disable-blink-features=AutomationControlled",
35
+ "user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36",
36
+ ]
37
+
38
+
39
+ class SeleniumUts:
40
+ driver = None
41
+
42
+ default_download_path = None
43
+ current_download_path = None
44
+
45
+ def close(self):
46
+ """
47
+ Desc:
48
+ Close the browser.\n
49
+ Args: None
50
+ """
51
+ if self.driver:
52
+ self.driver.quit()
53
+ self.driver = None
54
+
55
+ def wait_loads(self, tm=5):
56
+ """
57
+ Desc:
58
+ Wait for the page to load completely.\n
59
+ Args:
60
+ - ``tm`` - Additional time to wait after the page is loaded in seconds. Default is 5 seconds.
61
+ Returns: None
62
+ """
63
+ wait = WebDriverWait(self.driver, tm)
64
+ wt = lambda a: self.driver.execute_script(
65
+ 'return document.readyState=="complete";'
66
+ )
67
+ wait.until(wt)
68
+
69
+ def open_page(self, page):
70
+ """
71
+ Desc:
72
+ Open a page in the browser.\n
73
+ and wait for it to load.\n
74
+ Args:
75
+ - ``page`` - The URL of the page to be opened.
76
+ Returns:
77
+ - The WebDriver instance.
78
+ """
79
+ self.driver.get(page)
80
+ self.driver.implicitly_wait(2)
81
+ self.wait_loads()
82
+
83
+ return self.driver
84
+
85
+ def wait_xpath(self, path, time=20, multiple=False, throw=True, custom_error=None):
86
+ """
87
+ Desc:
88
+ Wait for an element to be visible using its XPATH.\n
89
+ Args:
90
+ - ``path`` - The XPATH of the element to be waited for.
91
+ - ``time`` - Maximum time to wait for the element in seconds. Default is 20 seconds.
92
+ - ``throw`` - If True, raises an exception if the element is not found within the time limit.
93
+ Returns:
94
+ - The WebElement if found, otherwise None.
95
+ """
96
+ try:
97
+ if multiple:
98
+ # Espera até que TODOS os elementos correspondentes estejam visíveis
99
+ elements = WebDriverWait(self.driver, time).until(
100
+ lambda d: self.driver.find_elements(
101
+ By.XPATH,
102
+ path,
103
+ selenium_uts=self,
104
+ time=time,
105
+ custom_error=custom_error,
106
+ )
107
+ )
108
+ return elements
109
+ else:
110
+ element = WebDriverWait(self.driver, time).until(
111
+ lambda d: self.driver.find_element(
112
+ By.XPATH,
113
+ path,
114
+ selenium_uts=self,
115
+ time=time,
116
+ custom_error=custom_error,
117
+ )
118
+ )
119
+ return element
120
+ except Exception:
121
+ if throw:
122
+ if custom_error:
123
+ raise Exception(custom_error)
124
+ else:
125
+ raise
126
+ return None
127
+
128
+ def wait_css(self, selector, time=20, throw=True, custom_error=None):
129
+ """
130
+ Desc:
131
+ Wait for an element to be visible using its CSS selector.\n
132
+ Args:
133
+ - ``selector`` - The CSS selector of the element to be waited for.
134
+ - ``time`` - Maximum time to wait for the element in seconds. Default is 20 seconds.
135
+ - ``throw`` - If True, raises an exception if the element is not found within the time limit.
136
+ Returns:
137
+ - The WebElement if found, otherwise None.
138
+ """
139
+ try:
140
+ element = WebDriverWait(self.driver, time).until(
141
+ EC.visibility_of_element_located((By.CSS_SELECTOR, selector))
142
+ )
143
+ return element
144
+ except Exception:
145
+ if throw:
146
+ if custom_error:
147
+ raise Exception(custom_error)
148
+ else:
149
+ raise
150
+ return None
151
+
152
+ def wait_id(self, element_id, time=10, throw=True, custom_error=None):
153
+ """
154
+ Desc:
155
+ Wait for an element to be present using its ID.\n
156
+ Args:
157
+ - ``element_id`` - The ID of the element to be waited for.
158
+ - ``time`` - Maximum time to wait for the element in seconds. Default is 10 seconds.
159
+ - ``throw`` - If True, raises an exception if the element is not found within the time limit.
160
+ Returns:
161
+ - The WebElement if found, otherwise None.
162
+ """
163
+ try:
164
+ elem = WebDriverWait(self.driver, time).until(
165
+ lambda d: self.driver.find_element(
166
+ By.ID,
167
+ element_id,
168
+ selenium_uts=self,
169
+ time=time,
170
+ custom_error=custom_error,
171
+ )
172
+ )
173
+ return elem
174
+ except Exception:
175
+ if throw:
176
+ if custom_error:
177
+ raise Exception(custom_error)
178
+ else:
179
+ raise
180
+ return None
181
+
182
+ def scroll_end(self):
183
+ """
184
+ Desc:
185
+ Scroll to the end of the page.\n
186
+ Args: None
187
+ """
188
+
189
+ get_pos = lambda: self.driver.execute_script(
190
+ "return document.documentElement.scrollTop"
191
+ )
192
+
193
+ while True:
194
+ atual_pos = get_pos()
195
+ self.driver.execute_script(
196
+ "window.scrollTo(0, document.body.scrollHeight);"
197
+ )
198
+ sleep(2)
199
+ future_pos = get_pos()
200
+ if future_pos == atual_pos:
201
+ break
202
+
203
+ def accept_alert(self, time=10):
204
+ """
205
+ Desc:
206
+ Wait for an alert to be present and accept it.\n
207
+ Args:
208
+ - ``time`` - Maximum time to wait for the alert in seconds. Default is 10 seconds.
209
+ Returns:
210
+ - The text of the alert.
211
+ """
212
+ try:
213
+ WebDriverWait(self.driver, time).until(EC.alert_is_present())
214
+ alert = self.driver.switch_to.alert
215
+ txt = alert.text
216
+ alert.accept()
217
+ return txt
218
+ except Exception:
219
+ return None
220
+
221
+ def disable_animations(self):
222
+ css_kill_animations = """
223
+ /* 1. Mata as durações */
224
+ *, *::before, *::after {
225
+ transition-duration: 0s !important;
226
+ transition-delay: 0s !important;
227
+ animation-duration: 0s !important;
228
+ animation-delay: 0s !important;
229
+ }
230
+
231
+ /* 2. Força a visibilidade imediata de elementos que dependem de animação para aparecer */
232
+ [style*="opacity: 0"],
233
+ [style*="opacity:0"],
234
+ .fade, .collapse, .hidden {
235
+ opacity: 1 !important;
236
+ display: block !important;
237
+ visibility: visible !important;
238
+ }
239
+
240
+ /* 3. Reseta transformações que deixariam o elemento fora da tela (comum em slide-ins) */
241
+ * {
242
+ transform: none !important;
243
+ perspective: none !important;
244
+ }
245
+ """
246
+
247
+ self.add_style(css_kill_animations)
248
+
249
+ def new_tab(self):
250
+ """
251
+ Desc:
252
+ Open a new browser tab and switch to it.\n
253
+ Returns: None
254
+ """
255
+ self.driver.execute_script("window.open('');")
256
+ windows = self.driver.window_handles
257
+ self.driver.switch_to.window(windows[-1])
258
+
259
+ def switch_to_new_tab(self):
260
+ """
261
+ Desc:
262
+ Switch to the most recently opened browser window.\n
263
+ Returns: None
264
+ """
265
+ windows = self.driver.window_handles
266
+ self.driver.switch_to.window(windows[-1])
267
+
268
+ def close_current_tab(self):
269
+ """
270
+ Desc:
271
+ Close the current browser tab and switch to the previous one.\n
272
+ Returns: None
273
+ """
274
+ all_windows = self.driver.window_handles
275
+
276
+ if len(all_windows) > 1:
277
+ # 1. Identifica qual é a aba atual antes de fechar
278
+ current_window = self.driver.current_window_handle
279
+
280
+ # 2. Encontra o índice da aba atual na lista de abas
281
+ current_index = all_windows.index(current_window)
282
+
283
+ # 3. Fecha a aba atual
284
+ self.driver.close()
285
+
286
+ # 4. Define o destino: a aba anterior (index - 1)
287
+ # ou a primeira aba se a atual for a única restando
288
+ new_window = all_windows[current_index - 1]
289
+
290
+ self.driver.switch_to.window(new_window)
291
+
292
+ def back_main_tab(self):
293
+ """
294
+ Desc:
295
+ Switch back to the first browser tab.\n
296
+ Returns: None
297
+ """
298
+ windows = self.driver.window_handles
299
+ self.driver.switch_to.window(windows[0])
300
+
301
+ def go_to_tab(self, index):
302
+ """
303
+ Desc:
304
+ Switch to a specific browser tab by index.\n
305
+ Args:
306
+ - ``index`` - The index of the tab to switch to (0-based).
307
+ Returns: None
308
+ """
309
+ windows = self.driver.window_handles
310
+ if index < len(windows):
311
+ self.driver.switch_to.window(windows[index])
312
+
313
+ def element_exists_xpath(self, xpath, time=5):
314
+ """
315
+ Desc:
316
+ Check if an element exists by XPATH.\n
317
+ Args:
318
+ - ``xpath`` - The XPATH of the element to be checked.
319
+ - ``time`` - Maximum time to wait for the element in seconds. Default is 5 seconds.
320
+ Returns:
321
+ - True if the element exists, False otherwise.
322
+ """
323
+ try:
324
+ WebDriverWait(self.driver, time).until(
325
+ EC.visibility_of_element_located((By.XPATH, xpath))
326
+ )
327
+ return True
328
+ except Exception:
329
+ return False
330
+
331
+ def element_exists_css(self, selector, time=5):
332
+ """
333
+ Desc:
334
+ Check if an element exists by CSS selector.\n
335
+ Args:
336
+ - ``selector`` - The CSS selector of the element to be checked.
337
+ - ``time`` - Maximum time to wait for the element in seconds. Default is 5 seconds.
338
+ Returns:
339
+ - True if the element exists, False otherwise.
340
+ """
341
+ try:
342
+ WebDriverWait(self.driver, time).until(
343
+ EC.presence_of_element_located((By.CSS_SELECTOR, selector))
344
+ )
345
+ return True
346
+ except Exception:
347
+ return False
348
+
349
+ def element_exists(self, by, value, time=5):
350
+ """
351
+ Desc:
352
+ Check if an element exists by a given locator strategy.\n
353
+ Args:
354
+ - ``by`` - The locator strategy (e.g., By.ID, By.XPATH, By.CSS_SELECTOR).
355
+ - ``value`` - The value of the locator.
356
+ - ``time`` - Maximum time to wait for the element in seconds. Default is 5 seconds.
357
+ Returns:
358
+ - True if the element exists, False otherwise.
359
+ """
360
+ try:
361
+ WebDriverWait(self.driver, time).until(
362
+ EC.presence_of_element_located((by, value))
363
+ )
364
+ return True
365
+ except Exception:
366
+ return False
367
+
368
+ def change_download_path(self, download_path):
369
+ self.driver.execute_cdp_cmd(
370
+ "Page.setDownloadBehavior",
371
+ {"behavior": "allow", "downloadPath": str(Path(download_path).resolve())},
372
+ )
373
+ self.current_download_path = download_path
374
+
375
+ def restore_download_path(self):
376
+ self.driver.execute_cdp_cmd(
377
+ "Page.setDownloadBehavior",
378
+ {
379
+ "behavior": "allow",
380
+ "downloadPath": str(Path(self.default_download_path).resolve()),
381
+ },
382
+ )
383
+ self.current_download_path = self.default_download_path
384
+
385
+ def wait_downloads_done(
386
+ self, timeout_start=10, timeout_end=60, file_path=None, escape=False
387
+ ):
388
+ temp_files = (
389
+ lambda: glob(f"{self.current_download_path}/*.crdownload")
390
+ + glob(f"{self.current_download_path}/*.tmp")
391
+ + glob(f"{self.current_download_path}/*.part")
392
+ )
393
+
394
+ scape_files = lambda: glob(
395
+ f"{self.current_download_path}/{glob.escape(file_path)}"
396
+ )
397
+ not_scape_files = lambda: glob(f"{self.current_download_path}/{file_path}")
398
+
399
+ if file_path:
400
+ start_time = time()
401
+ while not (scape_files() if escape else not_scape_files()):
402
+ if time() - start_time >= timeout_end:
403
+ raise Exception("Download file not detected")
404
+
405
+ while temp_files():
406
+ sleep(0.3)
407
+ return scape_files() if escape else not_scape_files()
408
+
409
+ # AGUARDA OS DOWNLOADS INICIAREM
410
+ start_time = time()
411
+ while not temp_files():
412
+ if time() - start_time >= timeout_start:
413
+ raise Exception("Download files not detected")
414
+
415
+ while temp_files():
416
+ sleep(0.3)
417
+
418
+ def get_last_download_file(self):
419
+ caminho_pasta = Path(self.current_download_path)
420
+ if not caminho_pasta.exists():
421
+ return None
422
+
423
+ arquivos = [
424
+ f
425
+ for f in caminho_pasta.iterdir()
426
+ if f.is_file() and not f.name.endswith((".crdownload", ".tmp", ".part"))
427
+ ]
428
+ if not arquivos:
429
+ return None
430
+
431
+ # Ordenamos pelo mtime (Modification Time)
432
+ # No Windows e Linux, isso representa quando o download terminou de ser escrito.
433
+ ultimo_arquivo = max(arquivos, key=lambda f: f.stat().st_mtime)
434
+
435
+ return str(ultimo_arquivo.absolute())
436
+
437
+ def full_screenshot(self, path):
438
+ self.scroll_end()
439
+ # 1. Pegar a altura total do documento via JavaScript
440
+ total_height = self.driver.execute_script(
441
+ "return document.body.parentNode.scrollHeight"
442
+ )
443
+ total_width = self.driver.execute_script(
444
+ "return document.body.parentNode.scrollWidth"
445
+ )
446
+
447
+ self.driver.execute_cdp_cmd(
448
+ "Emulation.setDeviceMetricsOverride",
449
+ {
450
+ "width": total_width,
451
+ "height": total_height,
452
+ "deviceScaleFactor": 1,
453
+ "mobile": False,
454
+ },
455
+ )
456
+
457
+ # 2. Redimensionar a janela para o tamanho total da página
458
+ sleep(1)
459
+
460
+ # 3. Tirar o print padrão
461
+ self.driver.save_screenshot(path)
462
+
463
+ def save_to_pdf(self, path, single_page=False):
464
+ # O comando retorna um dicionário com os dados em Base64
465
+ params = {"printBackground": True, "landscape": False}
466
+ if single_page:
467
+ # Dividimos por 96 porque o padrão de tela é 96 DPI
468
+ dimensions = self.driver.execute_script("""
469
+ return {
470
+ width: document.documentElement.offsetWidth / 96,
471
+ height: document.documentElement.scrollHeight / 96
472
+ };
473
+ """)
474
+
475
+ params = {
476
+ **params,
477
+ "paperHeight": dimensions["height"],
478
+ "marginTop": 0,
479
+ "marginBottom": 0,
480
+ "marginLeft": 0,
481
+ "marginRight": 0,
482
+ "pageRanges": "1", # Garante que ele foque na primeira (e única) página
483
+ }
484
+
485
+ result = self.driver.execute_cdp_cmd("Page.printToPDF", params)
486
+
487
+ # Salva o arquivo no diretório que você escolher agora
488
+ with open(path, "wb") as f:
489
+ f.write(base64.b64decode(result["data"]))
490
+
491
+ def add_print_style(self):
492
+ """
493
+ Injeta regras de CSS para garantir que as cores e fundos
494
+ sejam preservados durante a impressão/PDF.
495
+ """
496
+ css_code = """
497
+ var style = document.createElement('style');
498
+ style.type = 'text/css';
499
+ style.innerHTML = `
500
+ @media print {
501
+ body, .info-bar, .container, .section h3 {
502
+ -webkit-print-color-adjust: exact !important;
503
+ print-color-adjust: exact !important;
504
+ color-adjust: exact !important;
505
+ }
506
+ }
507
+ `;
508
+ document.getElementsByTagName('head')[0].appendChild(style);
509
+ """
510
+ self.driver.execute_script(css_code)
511
+
512
+ def add_style(self, css_content):
513
+ """
514
+ Injeta um bloco de CSS dinamicamente na página atual.
515
+ """
516
+ script = """
517
+ var style = document.createElement('style');
518
+ style.type = 'text/css';
519
+ if (style.styleSheet){
520
+ style.styleSheet.cssText = arguments[0];
521
+ } else {
522
+ style.appendChild(document.createTextNode(arguments[0]));
523
+ }
524
+ document.getElementsByTagName('head')[0].appendChild(style);
525
+ """
526
+ self.driver.execute_script(script, css_content)
527
+
528
+ def startRemoteSelenium(
529
+ self,
530
+ host,
531
+ name="default",
532
+ cust_opt=[],
533
+ cust_prefs=[],
534
+ remove_default_options=False,
535
+ download_path=None,
536
+ selenoid_browser=("chrome", "128.0"),
537
+ profile=None,
538
+ ) -> webdriver:
539
+ self.default_download_path = download_path
540
+ self.current_download_path = download_path
541
+
542
+ # ===================== OPTIONS ==============================
543
+ options = []
544
+ if not remove_default_options:
545
+ options = DEFAULT_OPTIONS
546
+ options += cust_opt
547
+
548
+ web_options = webdriver.ChromeOptions()
549
+ for op in options:
550
+ web_options.add_argument(op)
551
+
552
+ if profile:
553
+ web_options.add_argument(r"user-data-dir={}".format(profile))
554
+
555
+ web_options.headless = False
556
+
557
+ # ==================== PREFERENCES ===========================
558
+ prefs = {
559
+ "download.default_directory": str(Path(download_path).resolve()),
560
+ "savefile.default_directory": str(Path(download_path).resolve()),
561
+ "download.directory_upgrade": True,
562
+ "download.prompt_for_download": False,
563
+ "safebrowsing.enabled": False,
564
+ "download.directory_upgrade": True,
565
+ "credentials_enable_service": False,
566
+ "profile.password_manager_enabled": False,
567
+ "autofill.profile_enabled": False,
568
+ "plugins.always_open_pdf_externally": True,
569
+ "profile.password_manager_leak_detection": False,
570
+ "printing.print_preview_sticky_settings.appState": '{"recentDestinations":[{"id":"Save as PDF","origin":"local","account":""}],"selectedDestinationId":"Save as PDF","version":2}',
571
+ }
572
+ prefs = {**prefs, **cust_prefs}
573
+ web_options.add_experimental_option("prefs", prefs)
574
+
575
+ # ================== START BROWSER ===========================
576
+
577
+ web_options.add_experimental_option("useAutomationExtension", False)
578
+ web_options.add_experimental_option("excludeSwitches", ["enable-automation"])
579
+
580
+ CAPABILITIES["name"] = name
581
+ CAPABILITIES["browserName"] = selenoid_browser[0]
582
+ CAPABILITIES["version"] = selenoid_browser[1]
583
+ web_options.set_capability(name="selenoid:options", value=CAPABILITIES)
584
+ web_options.set_capability(
585
+ name="browserName", value=CAPABILITIES["browserName"]
586
+ )
587
+
588
+ self.driver = CustomRemoteDriver(command_executor=host, options=web_options)
589
+ self.driver.maximize_window()
590
+ self.driver.implicitly_wait(10)
591
+
592
+ return self.driver
593
+
594
+ def startUC(
595
+ self,
596
+ version_main: int = 142,
597
+ enable_cdp_events: bool = True,
598
+ download_path: str = None,
599
+ custom_prefs: dict = {},
600
+ custom_args: list = [],
601
+ ):
602
+ self.default_download_path = download_path
603
+ self.current_download_path = download_path
604
+ options = uc.ChromeOptions()
605
+
606
+ # PREFS padrão
607
+ prefs = {
608
+ "credentials_enable_service": False,
609
+ "profile.password_manager_enabled": False,
610
+ "profile.password_manager_leak_detection": False,
611
+ "download.default_directory": str(Path(download_path).resolve()),
612
+ }
613
+ prefs.update(custom_prefs)
614
+ options.add_experimental_option("prefs", prefs)
615
+
616
+ # ARGUMENTOS padrão
617
+ default_args = DEFAULT_OPTIONS.copy()
618
+ default_args.extend(custom_args)
619
+
620
+ for arg in default_args:
621
+ options.add_argument(arg)
622
+
623
+ # REMOVIDO: options.add_experimental_option("detach", True)
624
+ # Isso QUEBRA o UC e gera o erro que você recebeu.
625
+
626
+ # start UC
627
+ driver = uc.Chrome(
628
+ options=options,
629
+ enable_cdp_events=enable_cdp_events,
630
+ version_main=version_main,
631
+ )
632
+
633
+ self.driver = driver
634
+ driver.implicitly_wait(10)
635
+ return driver
636
+
637
+ def startChrome(
638
+ self,
639
+ driver_path,
640
+ download_path: str = None,
641
+ custom_prefs: dict = {},
642
+ custom_options: list = [],
643
+ remove_default_options: bool = False,
644
+ profile: str = None,
645
+ binary_location: str = None,
646
+ ):
647
+ self.default_download_path = download_path
648
+ self.current_download_path = download_path
649
+
650
+ # ===================== OPTIONS ==============================
651
+ options = []
652
+ if not remove_default_options:
653
+ options = DEFAULT_OPTIONS
654
+ options += custom_options
655
+
656
+ web_options = webdriver.ChromeOptions()
657
+ if binary_location:
658
+ web_options.binary_location = binary_location
659
+ web_options.set_capability("unhandledPromptBehavior", "accept")
660
+ for op in options:
661
+ web_options.add_argument(op)
662
+
663
+ if profile:
664
+ web_options.add_argument(
665
+ r"user-data-dir={}".format(str(Path(profile).resolve()))
666
+ )
667
+
668
+ web_options.headless = False
669
+
670
+ # ==================== PREFERENCES ===========================
671
+ prefs = {
672
+ "download.default_directory": (
673
+ str(Path(download_path).resolve()) if download_path else None
674
+ ),
675
+ "savefile.default_directory": (
676
+ str(Path(download_path).resolve()) if download_path else None
677
+ ),
678
+ "download.directory_upgrade": True,
679
+ "download.prompt_for_download": False,
680
+ "safebrowsing.enabled": False,
681
+ "download.directory_upgrade": True,
682
+ "credentials_enable_service": False,
683
+ "profile.password_manager_enabled": False,
684
+ "autofill.profile_enabled": False,
685
+ "plugins.always_open_pdf_externally": True,
686
+ "profile.password_manager_leak_detection": False,
687
+ "printing.print_preview_sticky_settings.appState": '{"recentDestinations":[{"id":"Save as PDF","origin":"local","account":""}],"selectedDestinationId":"Save as PDF","version":2}',
688
+ }
689
+ prefs = {**prefs, **custom_prefs}
690
+ web_options.add_experimental_option("prefs", prefs)
691
+
692
+ service = Service(executable_path=driver_path)
693
+ driver = CustomChromeDriver(service=service, options=web_options)
694
+ driver.maximize_window()
695
+
696
+ self.driver = driver
697
+ return driver
@@ -0,0 +1,44 @@
1
+ from selenium.webdriver.remote.webdriver import WebDriver as RemoteWebDriver
2
+ from seleniumUts.webelement import CWebElement
3
+ from selenium.webdriver import Chrome
4
+ from selenium.webdriver.common.by import By
5
+
6
+
7
+ class CustomRemoteDriver(RemoteWebDriver):
8
+ def create_web_element(self, element_id):
9
+ return CWebElement(self, element_id)
10
+
11
+
12
+ class CustomChromeDriver(Chrome):
13
+ def create_web_element(self, element_id):
14
+ return CWebElement(self, element_id)
15
+
16
+ def find_element(
17
+ self, by=By.ID, value=None, selenium_uts=None, time=None, custom_error=None
18
+ ):
19
+ # Faz a busca normal
20
+ element = super().find_element(by, value)
21
+
22
+ # Injeta as informações de busca no objeto CWebElement recém-criado
23
+ if isinstance(element, CWebElement):
24
+ element._found_by = by
25
+ element._query_path = value
26
+ element.selenium_uts = selenium_uts
27
+ element.time = time
28
+ element.custom_error = custom_error
29
+
30
+ return element
31
+
32
+ # É importante fazer o mesmo para find_elements (lista)
33
+ def find_elements(
34
+ self, by=By.ID, value=None, selenium_uts=None, time=None, custom_error=None
35
+ ):
36
+ elements = super().find_elements(by, value)
37
+ for el in elements:
38
+ if isinstance(el, CWebElement):
39
+ el._found_by = by
40
+ el._query_path = value
41
+ el.selenium_uts = selenium_uts
42
+ el.time = time
43
+ el.custom_error = custom_error
44
+ return elements
File without changes
@@ -0,0 +1,43 @@
1
+ from selenium.webdriver.remote.webelement import WebElement
2
+ from selenium.webdriver.support.ui import Select
3
+ import time
4
+
5
+
6
+ class CWebElement(WebElement):
7
+ def __init__(self, *args, **kwargs):
8
+ super().__init__(*args, **kwargs)
9
+
10
+ def delayed_send(self, word, delay=0.5):
11
+ """
12
+ Desc:
13
+ Send keys to the element with a delay between each character.\n
14
+ Args:
15
+ - ``word`` - The string to be sent to the element.
16
+ - ``delay`` - The delay between each character in seconds.
17
+ Default: 0.5 seconds.
18
+ """
19
+ for c in word:
20
+ self.send_keys(c)
21
+ time.sleep(delay)
22
+
23
+ def focus(self):
24
+ """Foca no elemento"""
25
+ self.parent.execute_script("arguments[0].scrollIntoView(true);", self)
26
+ time.sleep(0.5)
27
+ self.parent.execute_script("arguments[0].focus();", self)
28
+ return self
29
+
30
+ def select_by_text(self, text):
31
+ """Seleciona item em dropdown pelo texto visível"""
32
+ Select(self).select_by_visible_text(text)
33
+ return self
34
+
35
+ def select_by_value(self, value):
36
+ """Seleciona item em dropdown pelo valor"""
37
+ Select(self).select_by_value(value)
38
+ return self
39
+
40
+ def click_js(self):
41
+ """Clica no elemento usando JavaScript (evita toggle indesejado)"""
42
+ self.driver.execute_script("arguments[0].click();", self)
43
+ return self
@@ -0,0 +1,141 @@
1
+ Metadata-Version: 2.4
2
+ Name: seleniumUts
3
+ Version: 1.1.1
4
+ Summary: Zdek Util libraries for Pythom coding
5
+ Home-page: https://github.com/ZdekPyPi/SeleniumUts
6
+ Author: Zdek Development team
7
+ License: MIT
8
+ Keywords: seleniumUts
9
+ Classifier: Development Status :: 5 - Production/Stable
10
+ Classifier: Intended Audience :: Education
11
+ Classifier: Operating System :: Microsoft :: Windows :: Windows 10
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Requires-Python: >=3.10
15
+ Description-Content-Type: text/markdown
16
+ Requires-Dist: undetected-chromedriver>=3.5.5
17
+ Requires-Dist: selenium>=4.15.2
18
+ Dynamic: author
19
+ Dynamic: classifier
20
+ Dynamic: description
21
+ Dynamic: description-content-type
22
+ Dynamic: home-page
23
+ Dynamic: keywords
24
+ Dynamic: license
25
+ Dynamic: requires-dist
26
+ Dynamic: requires-python
27
+ Dynamic: summary
28
+
29
+ # SeleniumUts
30
+
31
+ Uma biblioteca Python que encapsula algumas funcionalidades do Selenium WebDriver, facilitando a automação de navegadores para testes e raspagem de dados. A biblioteca suporta o uso do `undetected_chromedriver` e integra-se facilmente com o Selenoid para execução de testes em ambientes distribuídos.
32
+
33
+ ## Uso
34
+
35
+ ### Importando a Biblioteca
36
+
37
+ ```python
38
+ from seleniumUts import SeleniumUts
39
+ ```
40
+
41
+ ### Criando uma Instância de `SeleniumUts`
42
+
43
+ ```python
44
+ selenium_lib = SeleniumUts()
45
+ ```
46
+
47
+ ### Exemplos de Uso
48
+
49
+ #### Configurando o Selenium com ChromeDriver
50
+
51
+ ```python
52
+ # Configure o Selenium sem usar o Selenoid
53
+ selenium_lib.setupSelenium(host=None, use_selenoid=False)
54
+
55
+ # Abrir uma página web
56
+ driver = selenium_lib.open_page('https://www.example.com')
57
+
58
+ # Fechar o navegador
59
+ selenium_lib.close()
60
+ ```
61
+
62
+ #### Configurando o Selenium com Selenoid
63
+
64
+ ```python
65
+ # Configure o Selenium usando o Selenoid
66
+ selenoid_host = 'http://your-selenoid-server.com/wd/hub'
67
+ selenium_lib.setupSelenium(host=selenoid_host, use_selenoid=True)
68
+
69
+ # Abrir uma página web
70
+ driver = selenium_lib.open_page('https://www.example.com')
71
+
72
+ # Fechar o navegador
73
+ selenium_lib.close()
74
+ ```
75
+
76
+ #### Aguardando a Visibilidade de um Elemento
77
+
78
+ ```python
79
+ # Configure o Selenium
80
+ selenium_lib.setupSelenium(host=None, use_selenoid=False)
81
+
82
+ # Abrir uma página web
83
+ selenium_lib.open_page('https://www.example.com')
84
+
85
+ # Esperar até que o elemento esteja visível
86
+ element = selenium_lib.wait_xpath('//button[@id="submit"]', time=10)
87
+ element.click()
88
+
89
+ # Fechar o navegador
90
+ selenium_lib.close()
91
+ ```
92
+
93
+ #### Envio de Texto com Atraso entre Caracteres
94
+
95
+ ```python
96
+ # Configure o Selenium
97
+ selenium_lib.setupSelenium(host=None, use_selenoid=False)
98
+
99
+ # Abrir uma página web
100
+ selenium_lib.open_page('https://www.example.com')
101
+
102
+ # Encontrar o campo de texto e enviar texto com atraso
103
+ element = selenium_lib.wait_xpath('//input[@id="search-box"]')
104
+ element.delayed_send('Python Selenium', delay=0.2)
105
+
106
+ # Fechar o navegador
107
+ selenium_lib.close()
108
+ ```
109
+
110
+ #### Rolagem até o Fim da Página
111
+
112
+ ```python
113
+ # Configure o Selenium
114
+ selenium_lib.setupSelenium(host=None, use_selenoid=False)
115
+
116
+ # Abrir uma página web
117
+ selenium_lib.open_page('https://www.example.com')
118
+
119
+ # Rolagem até o fim da página
120
+ selenium_lib.scroll_end()
121
+
122
+ # Fechar o navegador
123
+ selenium_lib.close()
124
+ ```
125
+
126
+ ## Métodos Disponíveis
127
+
128
+ - **`setupSelenium(host, name="default", use_selenoid=False, cust_opt=[], remove_default_options=False, download_path=None, selenoid_browser=("chrome","110.0"))`**: Configura o WebDriver do Selenium com opções personalizadas e preferências para o ChromeDriver. Suporta configuração para Selenoid.
129
+ - **`open_page(page)`**: Abre uma página web e espera até que ela seja totalmente carregada.
130
+ - **`wait_xpath(path, time=20, throw=True)`**: Aguarda até que um elemento, identificado por um caminho XPath, esteja visível no DOM.
131
+ - **`<el>.delayed_send(word, delay)`**: Envia texto para um elemento, inserindo um atraso especificado entre cada caractere.
132
+ - **`scroll_end()`**: Rola até o final da página atual.
133
+ - **`close()`**: Fecha o navegador e encerra a sessão do WebDriver.
134
+
135
+ ## Contribuição
136
+
137
+ Contribuições são bem-vindas! Por favor, envie um pull request ou abra uma issue para quaisquer problemas ou melhorias.
138
+
139
+ ## Licença
140
+
141
+ Este projeto está licenciado sob a licença MIT.
@@ -0,0 +1,8 @@
1
+ seleniumUts/__init__.py,sha256=QzMr-N06WTh37AAdjgRc_Nw0ZWKn6X8fCNKgbz5TYu8,23984
2
+ seleniumUts/custom_driver.py,sha256=ffzeRl3Uhccfo47jj61DWMuPHSBMJwT-mAV0BaT0lr8,1536
3
+ seleniumUts/seleniumuts.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ seleniumUts/webelement.py,sha256=ccf-zTdipXfNiQyVlgJl17jLo9xe3pIrBQcBPy3jkr8,1408
5
+ seleniumuts-1.1.1.dist-info/METADATA,sha256=UjOD3xpkcfGCuO1z6fFY7GSloUxDXxP-TCRvjG68ZZA,4148
6
+ seleniumuts-1.1.1.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
7
+ seleniumuts-1.1.1.dist-info/top_level.txt,sha256=DSdtNU4ul1OiKP-wVWtW9-nNeK5jtIkp3bKq5xGO1Ns,12
8
+ seleniumuts-1.1.1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.10.2)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ seleniumUts