selmate 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.
selmate/constants.py ADDED
@@ -0,0 +1,329 @@
1
+ import re
2
+
3
+ WHITESPACE_PATTERN = re.compile(r'\s+')
4
+ WINDOW_LOCATION_HREF_JS_PATTERN = re.compile(r"window\.location\.href=['\"](.*?)['\"]")
5
+
6
+ CONFIRMATIONS = [
7
+ # English
8
+ "[x] accept all",
9
+ "[x] accept all cookies",
10
+ "☑️",
11
+ "☑️ accept all",
12
+ "☑️ accept all cookies",
13
+ "✓",
14
+ "✔",
15
+ "✔ agree to all",
16
+ "✅",
17
+ "✅ allow all",
18
+ "✅ allow all cookies",
19
+ "accept",
20
+ "accept cookies",
21
+ "accept all",
22
+ "accept all cookies",
23
+ "accept and continue",
24
+ "accept cookies and continue",
25
+ "accept everything",
26
+ "acknowledge",
27
+ "acknowledged",
28
+ "agree",
29
+ "agree to all",
30
+ "agree to all cookies",
31
+ "agree to everything",
32
+ "allow",
33
+ "allow cookies",
34
+ "allow all",
35
+ "allow all cookies",
36
+ "approve",
37
+ "approve all",
38
+ "approved",
39
+ "confirm",
40
+ "confirm cookies",
41
+ "confirm all",
42
+ "confirm all cookies",
43
+ "confirmed",
44
+ "consent",
45
+ "consent cookies",
46
+ "consent to all",
47
+ "consent to all cookies",
48
+ "consent to everything",
49
+ "continue",
50
+ "enter",
51
+ "enable all",
52
+ "enable all cookies",
53
+ "I accept",
54
+ "I accept cookies",
55
+ "I accept all cookies",
56
+ "I acknowledge",
57
+ "I am 18 or older - Enter",
58
+ "I am over 18",
59
+ "I agree",
60
+ "I agree cookies",
61
+ "I agree all cookies",
62
+ "I allow",
63
+ "I allow cookies",
64
+ "I allow all cookies",
65
+ "I approve",
66
+ "I confirm",
67
+ "I confirm cookies",
68
+ "I confirm all cookies",
69
+ "I consent",
70
+ "I give my consent",
71
+ "I have read and agree",
72
+ "I permit",
73
+ "I understand",
74
+ "proceed",
75
+ "select all",
76
+ "yes",
77
+ "yes, continue",
78
+ "yes, I am",
79
+ "yes, I am under",
80
+ "yes, I agree",
81
+ "okay",
82
+ "I okay",
83
+ "alright",
84
+ "I alright",
85
+
86
+ # Русский
87
+ "активировать все",
88
+ "включить все",
89
+ "всё принято",
90
+ "всё понятно",
91
+ "выбрать всё",
92
+ "да",
93
+ "да, согласен",
94
+ "да, согласна",
95
+ "даю согласие",
96
+ "одобрить все",
97
+ "подтверждаю",
98
+ "подтверждение",
99
+ "подтвердить все",
100
+ "принимаю",
101
+ "принимаю все",
102
+ "принимаю условия",
103
+ "принять всё",
104
+ "принять все",
105
+ "разрешаю",
106
+ "разрешаю все",
107
+ "разрешить все",
108
+ "согласен",
109
+ "согласен на обработку данных",
110
+ "согласен со всем",
111
+ "согласна",
112
+ "согласие",
113
+ "соглашаюсь",
114
+ "согласиться со всем",
115
+ "я даю согласие",
116
+ "я разрешаю",
117
+ "я соглашаюсь",
118
+ "я согласен",
119
+ "я согласна",
120
+ "продолжить",
121
+ "ок",
122
+ "я подтверждаю",
123
+
124
+ # Українська
125
+ "всё прийнято",
126
+ "все зрозуміло",
127
+ "вибрати все",
128
+ "дозволити все",
129
+ "дозволяю",
130
+ "затвердити все",
131
+ "згоден",
132
+ "згодна",
133
+ "надаю згоду",
134
+ "підтверджую",
135
+ "погоджуюсь",
136
+ "погоджуюсь з усім",
137
+ "приймаю",
138
+ "приймаю все",
139
+ "прийняти все",
140
+ "так",
141
+ "так, згоден",
142
+ "так, згодна",
143
+ "я дозволяю",
144
+ "я надаю згоду",
145
+ "я погоджуюсь",
146
+ "я підтверджую",
147
+ "я згоден",
148
+ "я згодна",
149
+
150
+ # Deutsch
151
+ "akzeptieren",
152
+ "alle akzeptieren",
153
+ "alle annehmen",
154
+ "alle bestätigen",
155
+ "alle erlauben",
156
+ "allen zustimmen",
157
+ "bestätigen",
158
+ "einverstanden",
159
+ "erlauben",
160
+ "ich akzeptiere",
161
+ "ich bestätige",
162
+ "ich bin einverstanden",
163
+ "ich erlaube",
164
+ "ich stimme zu",
165
+ "ja",
166
+ "ja, ich stimme zu",
167
+ "okay",
168
+ "ich okay",
169
+
170
+ # Français
171
+ "accepté",
172
+ "accepter tout",
173
+ "autoriser",
174
+ "confirmer",
175
+ "consentir",
176
+ "d'accord",
177
+ "j'accepte",
178
+ "j'autorise",
179
+ "je confirme",
180
+ "je consens",
181
+ "je suis d'accord",
182
+ "oui",
183
+ "oui, je suis d'accord",
184
+ "tout accepter",
185
+ "tout autoriser",
186
+ "approuver tout",
187
+ "bien",
188
+ "je bien",
189
+
190
+ # Español
191
+ "aceptar todo",
192
+ "acepto",
193
+ "aprobar todo",
194
+ "confirmar todo",
195
+ "consiento",
196
+ "de acuerdo",
197
+ "estoy de acuerdo",
198
+ "permítir",
199
+ "permitir todo",
200
+ "sí",
201
+ "sí, acepto",
202
+ "yo permito",
203
+ "vale",
204
+ "está bien",
205
+
206
+ # Italiano
207
+ "accetta tutto",
208
+ "accetto",
209
+ "approva tutto",
210
+ "confermo",
211
+ "consento",
212
+ "consenti a tutto",
213
+ "sì",
214
+ "sì, accetto",
215
+ "sono d'accordo",
216
+ "va bene",
217
+
218
+ # Português
219
+ "aceitar tudo",
220
+ "aceito",
221
+ "aprovar tudo",
222
+ "concordo",
223
+ "confirmo",
224
+ "consinto",
225
+ "eu aceito",
226
+ "eu concordo",
227
+ "permitir tudo",
228
+ "sim",
229
+ "sim, eu concordo",
230
+ "tudo bem",
231
+
232
+ # Polski
233
+ "akceptuję",
234
+ "potwierdzam",
235
+ "tak",
236
+ "tak, zgadzam się",
237
+ "wyrażam zgodę",
238
+ "zgoda",
239
+ "zgoda na wszystko",
240
+ "zaakceptuj wszystko",
241
+ "zatwierdź wszystko",
242
+ "dobrze",
243
+
244
+ # Nederlands
245
+ "accepteer",
246
+ "akkoord",
247
+ "alles accepteren",
248
+ "alles goedkeuren",
249
+ "alles toestaan",
250
+ "bevestig",
251
+ "ik accepteer",
252
+ "ik bevestig",
253
+ "ik ga akkoord",
254
+ "oke",
255
+
256
+ # Svenska (Swedish)
257
+ "acceptera",
258
+ "acceptera alla",
259
+ "godkänn",
260
+ "godkänn alla",
261
+ "godkänner",
262
+ "jag accepterar",
263
+ "jag godkänner",
264
+ "jag samtycker",
265
+ "samtycke",
266
+ "tillåt alla",
267
+ "okej",
268
+
269
+ # Dansk (Danish)
270
+ "accepter",
271
+ "accepter alle",
272
+ "godkend",
273
+ "godkend alle",
274
+ "jeg accepterer",
275
+ "jeg godkender",
276
+ "tillad alle",
277
+ "okay",
278
+
279
+ # Norsk (Norwegian)
280
+ "aksepter",
281
+ "aksepter alle",
282
+ "godkjenn",
283
+ "godkjenn alle",
284
+ "jeg aksepterer",
285
+ "jeg godkjenner",
286
+ "tillat alle",
287
+ "greit",
288
+
289
+ # Suomi (Finnish)
290
+ "hyväksy kaikki",
291
+ "salli kaikki",
292
+ "ok",
293
+
294
+ # 中文 (Chinese)
295
+ "同意",
296
+ "我同意",
297
+ "接受",
298
+ "确认",
299
+ "好",
300
+
301
+ # 日本語 (Japanese)
302
+ "はい",
303
+ "予",
304
+ "同意する",
305
+ "承諾する",
306
+ "確認",
307
+ "オーケー",
308
+
309
+ # 한국어 (Korean)
310
+ "동의",
311
+ "동의합니다",
312
+ "확인",
313
+ "예",
314
+ "좋아요",
315
+
316
+ # Türkçe (Turkish)
317
+ "evet",
318
+ "kabul ediyorum",
319
+ "katılıyorum",
320
+ "onaylıyorum",
321
+ "tamam",
322
+
323
+ # العربية (Arabic)
324
+ "أقر",
325
+ "أوافق",
326
+ "أوافق على الشروط",
327
+ "نعم",
328
+ "حسنا",
329
+ ]
@@ -0,0 +1,6 @@
1
+ HUMAN_CLICK_LATENCY = (0.1, 0.3)
2
+ HUMAN_MOUSE_MOVE_LATENCY = (0.01, 0.03)
3
+ HUMAN_FOCUS_ELEMENT_LATENCY = (0.1, 0.6)
4
+ HUMAN_OBSERVE_VIEW_LATENCY = (0.5, 1.0)
5
+ HUMAN_OBSERVE_PAGE_LATENCY = (2.0, 5.0)
6
+ HUMAN_SCROLL_LATENCY = (0.1, 0.7)
@@ -0,0 +1,41 @@
1
+ import time
2
+
3
+ from selmate.humanity.constants import HUMAN_CLICK_LATENCY, HUMAN_MOUSE_MOVE_LATENCY, HUMAN_FOCUS_ELEMENT_LATENCY, \
4
+ HUMAN_OBSERVE_VIEW_LATENCY, HUMAN_OBSERVE_PAGE_LATENCY, HUMAN_SCROLL_LATENCY
5
+ from selmate.utils import latency_time
6
+
7
+
8
+ def human_click_latency():
9
+ """Introduces a delay simulating human click latency.
10
+ """
11
+ time.sleep(latency_time(*HUMAN_CLICK_LATENCY))
12
+
13
+
14
+ def human_mouse_move_latency():
15
+ """Introduces a delay simulating human mouse movement latency.
16
+ """
17
+ time.sleep(latency_time(*HUMAN_MOUSE_MOVE_LATENCY))
18
+
19
+
20
+ def human_focus_element_latency():
21
+ """Introduces a delay simulating human element focus latency.
22
+ """
23
+ time.sleep(latency_time(*HUMAN_FOCUS_ELEMENT_LATENCY))
24
+
25
+
26
+ def human_observe_view_latency():
27
+ """Introduces a delay simulating human view observation latency.
28
+ """
29
+ time.sleep(latency_time(*HUMAN_OBSERVE_VIEW_LATENCY))
30
+
31
+
32
+ def human_observe_page_latency():
33
+ """Introduces a delay simulating human page observation latency.
34
+ """
35
+ time.sleep(latency_time(*HUMAN_OBSERVE_PAGE_LATENCY))
36
+
37
+
38
+ def human_scroll_latency():
39
+ """Introduces a delay simulating human scroll latency.
40
+ """
41
+ time.sleep(latency_time(*HUMAN_SCROLL_LATENCY))
@@ -0,0 +1,170 @@
1
+ from typing import List
2
+
3
+ from selenium.webdriver.remote.webelement import WebElement
4
+
5
+ from selmate.safe_exceptions import safe_stale, safe_not_found
6
+
7
+
8
+ def activate_mouse_path_drawing(driver):
9
+ """Adds a canvas to the page to draw mouse movement paths.
10
+ :param driver: The Selenium WebDriver instance.
11
+ """
12
+ driver.execute_script("""
13
+ const canvas = document.createElement('canvas');
14
+ canvas.width = window.innerWidth;
15
+ canvas.height = window.innerHeight;
16
+ canvas.style.position = 'fixed';
17
+ canvas.style.top = '0';
18
+ canvas.style.left = '0';
19
+ canvas.style.pointerEvents = 'none';
20
+ document.body.appendChild(canvas);
21
+ const ctx = canvas.getContext('2d');
22
+ ctx.strokeStyle = 'red';
23
+ ctx.lineWidth = 2;
24
+ let lastX, lastY;
25
+
26
+ document.addEventListener('mousemove', (e) => {
27
+ if (lastX && lastY) {
28
+ ctx.beginPath();
29
+ ctx.moveTo(lastX, lastY);
30
+ ctx.lineTo(e.clientX, e.clientY);
31
+ ctx.stroke();
32
+ }
33
+ lastX = e.clientX;
34
+ lastY = e.clientY;
35
+ });
36
+ """)
37
+
38
+
39
+ def js_choose_elements_above_z_index(min_z_index, driver, query_selector='*') -> List[WebElement]:
40
+ """Finds elements with a z-index above a minimum value.
41
+ :param min_z_index: Minimum z-index value.
42
+ :param driver: The Selenium WebDriver instance.
43
+ :param query_selector: CSS selector for elements.
44
+ :return: List of elements with z-index above the minimum.
45
+ """
46
+ return driver.execute_script(f"""
47
+ let elements = document.querySelectorAll('{query_selector}');
48
+ let result = [];
49
+ for (let el of elements) {{
50
+ let zIndex = window.getComputedStyle(el).zIndex;
51
+ if (zIndex !== 'auto' && parseInt(zIndex) >= {min_z_index}) {{
52
+ result.push(el);
53
+ }}
54
+ }}
55
+ return result;
56
+ """)
57
+
58
+
59
+ def js_find_elements(query_selector, driver):
60
+ """Finds elements matching a CSS selector.
61
+ :param query_selector: CSS selector for elements.
62
+ :param driver: The Selenium WebDriver instance.
63
+ :return: List of matching web elements.
64
+ """
65
+ return driver.execute_script(f"return document.querySelectorAll('{query_selector}');")
66
+
67
+
68
+ def js_smooth_scroll(to_x, to_y, driver):
69
+ """Performs a smooth scroll to specified coordinates.
70
+ :param to_x: Target x-coordinate.
71
+ :param to_y: Target y-coordinate.
72
+ :param driver: The Selenium WebDriver instance.
73
+ :return: None
74
+ """
75
+ driver.execute_script(f"window.scrollTo({to_x}, {to_y}, {{behaviour: 'smooth'}});")
76
+
77
+
78
+ @safe_stale(def_val=False)
79
+ def js_click(element: WebElement, driver) -> bool:
80
+ """Performs a JavaScript click on an element.
81
+ :param element: The web element to click.
82
+ :param driver: The Selenium WebDriver instance.
83
+ :return: True if the click was successful.
84
+ """
85
+ driver.execute_script('arguments[0].click();', element)
86
+ return True
87
+
88
+
89
+ @safe_not_found(def_val=False)
90
+ @safe_stale(def_val=False)
91
+ def js_is_full_in_viewport(element: WebElement, driver):
92
+ """Checks if an element is fully in the viewport.
93
+ :param element: The web element to check.
94
+ :param driver: The Selenium WebDriver instance.
95
+ :return: True if the element is fully visible.
96
+ """
97
+ return driver.execute_script(
98
+ """
99
+ var elem = arguments[0], box = elem.getBoundingClientRect();
100
+ return (
101
+ box.top >= 0 &&
102
+ box.left >= 0 &&
103
+ box.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
104
+ box.right <= (window.innerWidth || document.documentElement.clientWidth)
105
+ );
106
+ """,
107
+ element
108
+ )
109
+
110
+
111
+ @safe_not_found(def_val=False)
112
+ @safe_stale(def_val=False)
113
+ def js_is_partially_in_viewport(element: WebElement, driver):
114
+ """Checks if an element is partially in the viewport.
115
+ :param element: The web element to check.
116
+ :param driver: The Selenium WebDriver instance.
117
+ :return: True if the element is partially visible.
118
+ """
119
+ return driver.execute_script(
120
+ """
121
+ var elem = arguments[0], box = elem.getBoundingClientRect();
122
+ var windowHeight = window.innerHeight || document.documentElement.clientHeight;
123
+ var windowWidth = window.innerWidth || document.documentElement.clientWidth;
124
+ return (
125
+ box.bottom >= 0 &&
126
+ box.top <= windowHeight &&
127
+ box.right >= 0 &&
128
+ box.left <= windowWidth
129
+ );
130
+ """,
131
+ element
132
+ )
133
+
134
+
135
+ @safe_stale(def_val=False)
136
+ def js_need_scroll_to_element(element: WebElement, driver):
137
+ """Checks if scrolling is needed to bring an element into view.
138
+ :param element: The web element to check.
139
+ :param driver: The Selenium WebDriver instance.
140
+ :return: True if scrolling is needed.
141
+ """
142
+ return driver.execute_script(
143
+ """
144
+ var elem = arguments[0], box = elem.getBoundingClientRect();
145
+ return box.top < 0 || box.bottom > (window.innerHeight || document.documentElement.clientHeight);
146
+ """,
147
+ element
148
+ )
149
+
150
+
151
+ @safe_stale(def_val=False)
152
+ def js_scroll_to_element(element: WebElement, driver):
153
+ """Scrolls to an element using JavaScript.
154
+ :param element: The web element to scroll to.
155
+ :param driver: The Selenium WebDriver instance.
156
+ :return: True if the scroll was successful.
157
+ """
158
+ driver.execute_script("arguments[0].scrollIntoView({behavior: 'smooth', block: 'center'});", element)
159
+ return True
160
+
161
+
162
+ @safe_stale(def_val=False)
163
+ def js_remove_element(element: WebElement, driver):
164
+ """Removes an element from the DOM using JavaScript.
165
+ :param element: The web element to remove.
166
+ :param driver: The Selenium WebDriver instance.
167
+ :return: True if the removal was successful.
168
+ """
169
+ driver.execute_script("arguments[0].remove();", element)
170
+ return True
@@ -0,0 +1,34 @@
1
+ from functools import wraps
2
+
3
+ from selenium.common import StaleElementReferenceException, TimeoutException, MoveTargetOutOfBoundsException, \
4
+ ElementClickInterceptedException, NoSuchElementException, ElementNotInteractableException
5
+
6
+
7
+ def make_exception_safe_decorator(exception, default_value=None):
8
+ """Creates a decorator to handle specific Selenium exceptions.
9
+ :param exception: The exception type to catch.
10
+ :param default_value: The value to return on exception.
11
+ :return: A decorator function.
12
+ """
13
+ def safe_decorator(def_val=default_value):
14
+ def decorator(func):
15
+ @wraps(func)
16
+ def wrapper(*args, **kwargs):
17
+ try:
18
+ return func(*args, **kwargs)
19
+ except exception:
20
+ return def_val
21
+
22
+ return wrapper
23
+
24
+ return decorator
25
+
26
+ return safe_decorator
27
+
28
+
29
+ safe_stale = make_exception_safe_decorator(StaleElementReferenceException, None)
30
+ safe_timeout = make_exception_safe_decorator(TimeoutException, None)
31
+ safe_out_of_bound = make_exception_safe_decorator(MoveTargetOutOfBoundsException, None)
32
+ safe_click_interception = make_exception_safe_decorator(ElementClickInterceptedException, None)
33
+ safe_not_interactable = make_exception_safe_decorator(ElementNotInteractableException, None)
34
+ safe_not_found = make_exception_safe_decorator(NoSuchElementException, None)
@@ -0,0 +1,70 @@
1
+ from selenium.webdriver import ActionChains
2
+ from selenium.webdriver.remote.webelement import WebElement
3
+ from selenium.webdriver.support import expected_conditions
4
+ from selenium.webdriver.support.wait import WebDriverWait
5
+
6
+ from selmate.safe_exceptions import safe_out_of_bound, safe_stale, safe_timeout, safe_click_interception, \
7
+ safe_not_interactable
8
+
9
+
10
+ @safe_timeout(def_val=False)
11
+ def wait_selection(element: WebElement, driver, timeout=1.0):
12
+ """Waits for an element to be selected.
13
+ :param element: The web element to check for selection.
14
+ :param driver: The Selenium WebDriver instance.
15
+ :param timeout: Time to wait for the element to be selected.
16
+ :return: True if the element is selected, False otherwise.
17
+ """
18
+ return WebDriverWait(driver, timeout).until(
19
+ expected_conditions.element_to_be_selected(element)
20
+ )
21
+
22
+
23
+ @safe_not_interactable(def_val=False)
24
+ @safe_stale(def_val=False)
25
+ def selenium_element_center(element: WebElement):
26
+ """Calculates the center coordinates of a web element.
27
+ :param element: The web element to find the center of.
28
+ :return: Tuple of (x, y) coordinates of the element's center.
29
+ """
30
+ rect = element.rect
31
+ return rect['x'] + rect['width'] / 2, rect['y'] + rect['height'] / 2
32
+
33
+
34
+ @safe_not_interactable(def_val=False)
35
+ @safe_click_interception(def_val=False)
36
+ @safe_out_of_bound(def_val=False)
37
+ def selenium_click(element: WebElement):
38
+ """Performs a click on a web element.
39
+ :param element: The web element to click.
40
+ :return: True if the click was successful.
41
+ """
42
+ element.click()
43
+ return True
44
+
45
+
46
+ @safe_timeout(def_val=None)
47
+ def find_element_safely(by, value, driver, timeout=0.01):
48
+ """Safely finds an element on the page with a short timeout.
49
+ :param by: The method used to locate the element.
50
+ :param value: The value for the locator.
51
+ :param driver: The Selenium WebDriver instance.
52
+ :param timeout: The maximum time to wait for the element.
53
+ :return: The found web element or None if not found.
54
+ """
55
+ return WebDriverWait(driver, timeout).until(
56
+ expected_conditions.presence_of_element_located((by, value))
57
+ )
58
+
59
+
60
+ @safe_not_interactable(def_val=False)
61
+ @safe_out_of_bound(def_val=False)
62
+ @safe_stale(def_val=False)
63
+ def selenium_scroll_to_element(element: WebElement, driver):
64
+ """Scrolls to a web element using ActionChains.
65
+ :param element: The web element to scroll to.
66
+ :param driver: The Selenium WebDriver instance.
67
+ :return: True if the scroll was successful.
68
+ """
69
+ ActionChains(driver).move_to_element(element).perform()
70
+ return True