fantomas 0.1.2__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.
- fantomas/__init__.py +11 -0
- fantomas/fantomas_no_driver.py +475 -0
- fantomas/identity.py +91 -0
- fantomas/no_driver/CursorIllustration.py +35 -0
- fantomas/no_driver/Geometry.py +38 -0
- fantomas/no_driver/IframeManager.py +10 -0
- fantomas/proxy.py +193 -0
- fantomas/random_sleeper.py +6 -0
- fantomas/raw_chrome.py +31 -0
- fantomas/raw_screen.py +47 -0
- fantomas/screen.py +41 -0
- fantomas/secondary_flow.py +27 -0
- fantomas/utils.py +21 -0
- fantomas/virtual_cursor_path.py +76 -0
- fantomas/xdotool_actions.py +339 -0
- fantomas-0.1.2.dist-info/METADATA +8 -0
- fantomas-0.1.2.dist-info/RECORD +19 -0
- fantomas-0.1.2.dist-info/WHEEL +5 -0
- fantomas-0.1.2.dist-info/top_level.txt +1 -0
fantomas/__init__.py
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from .utils import get_value_or_default, load_config
|
|
2
|
+
from .fantomas_no_driver import *
|
|
3
|
+
from .identity import *
|
|
4
|
+
from .proxy import *
|
|
5
|
+
from .random_sleeper import *
|
|
6
|
+
from .raw_chrome import *
|
|
7
|
+
from .raw_screen import *
|
|
8
|
+
from .screen import *
|
|
9
|
+
from .secondary_flow import *
|
|
10
|
+
from .virtual_cursor_path import *
|
|
11
|
+
from .xdotool_actions import *
|
|
@@ -0,0 +1,475 @@
|
|
|
1
|
+
import random
|
|
2
|
+
import asyncio
|
|
3
|
+
from nodriver import *
|
|
4
|
+
from .no_driver.IframeManager import *
|
|
5
|
+
from .no_driver.Geometry import *
|
|
6
|
+
from .xdotool_actions import *
|
|
7
|
+
from .virtual_cursor_path import *
|
|
8
|
+
from .no_driver.CursorIllustration import *
|
|
9
|
+
from .raw_screen import RawScreen
|
|
10
|
+
from .raw_chrome import RawChrome
|
|
11
|
+
from .utils import get_value_or_default, load_config
|
|
12
|
+
from nodriver.core.browser import CookieJar
|
|
13
|
+
from nodriver.core.tab import Tab
|
|
14
|
+
import nodriver as uc
|
|
15
|
+
from typing import cast
|
|
16
|
+
|
|
17
|
+
class FantomasNoDriver():
|
|
18
|
+
def __init__(self,fantomas_params=None):
|
|
19
|
+
self.no_driver_instance = uc
|
|
20
|
+
self.fantomas_params = fantomas_params
|
|
21
|
+
self.browser_options = None
|
|
22
|
+
self.browser_extensions = None
|
|
23
|
+
self.emulate_movement = 0
|
|
24
|
+
self.show_cursor = 0
|
|
25
|
+
self.user_data_dir = "/tmp/uc_tbr34hha"
|
|
26
|
+
self.browser_executable_path = "/bin/google-chrome"
|
|
27
|
+
self.lang = "en-US"
|
|
28
|
+
self.headless = False
|
|
29
|
+
self.emulate_keyboard = 0
|
|
30
|
+
if self.fantomas_params:
|
|
31
|
+
self.parse_fantomas_params()
|
|
32
|
+
if self.browser_options and self.browser_extensions:
|
|
33
|
+
self.add_extensions()
|
|
34
|
+
|
|
35
|
+
def __getattr__(self, name):
|
|
36
|
+
return getattr(self.no_driver_instance, name)
|
|
37
|
+
|
|
38
|
+
async def launch_browser(self):
|
|
39
|
+
try:
|
|
40
|
+
await self.kill_old_chrome_process()
|
|
41
|
+
await asyncio.sleep(0.3)
|
|
42
|
+
self.no_driver_browser_instance = await self.no_driver_instance.start(
|
|
43
|
+
headless=self.headless,
|
|
44
|
+
browser_executable_path=self.browser_executable_path,
|
|
45
|
+
browser_args=self.browser_options,
|
|
46
|
+
lang=self.lang)
|
|
47
|
+
except Exception:
|
|
48
|
+
await self.kill_old_chrome_process()
|
|
49
|
+
await asyncio.sleep(0.3)
|
|
50
|
+
self.no_driver_browser_instance = await self.no_driver_instance.start(
|
|
51
|
+
headless=self.headless,
|
|
52
|
+
browser_executable_path=self.browser_executable_path,
|
|
53
|
+
browser_args=self.browser_options,
|
|
54
|
+
lang=self.lang)
|
|
55
|
+
|
|
56
|
+
return FantomasNoDriverBrowser(self.no_driver_browser_instance, self.emulate_movement, self.show_cursor, self.emulate_keyboard)
|
|
57
|
+
|
|
58
|
+
def parse_fantomas_params(self):
|
|
59
|
+
self.fantomas_params = load_config(self.fantomas_params)
|
|
60
|
+
self.browser_options = get_value_or_default(self.fantomas_params.get("fantomas_browser_options"), self.browser_options)
|
|
61
|
+
self.browser_extensions = get_value_or_default(self.fantomas_params.get("fantomas_browser_extensions"), self.browser_extensions)
|
|
62
|
+
self.emulate_movement = get_value_or_default(self.fantomas_params.get("fantomas_emulate_movement"), self.emulate_movement)
|
|
63
|
+
self.show_cursor = get_value_or_default(self.fantomas_params.get("fantomas_show_cursor"), self.show_cursor)
|
|
64
|
+
self.user_data_dir = get_value_or_default(self.fantomas_params.get("fantomas_user_data_dir"), self.user_data_dir)
|
|
65
|
+
self.browser_executable_path = get_value_or_default(self.fantomas_params.get("fantomas_browser_executable_path"), self.browser_executable_path)
|
|
66
|
+
self.lang = get_value_or_default(self.fantomas_params.get("fantomas_lang"), self.lang)
|
|
67
|
+
self.headless = get_value_or_default(self.fantomas_params.get("fantomas_headless"), self.headless)
|
|
68
|
+
self.emulate_keyboard = get_value_or_default(self.fantomas_params.get("fantomas_emulate_keyboard"), self.emulate_keyboard)
|
|
69
|
+
|
|
70
|
+
def add_extensions(self):
|
|
71
|
+
if self.browser_extensions:
|
|
72
|
+
argument_string = "--load-extension=" + ",".join(self.browser_extensions)
|
|
73
|
+
print(argument_string)
|
|
74
|
+
self.browser_options.append(argument_string)
|
|
75
|
+
|
|
76
|
+
@staticmethod
|
|
77
|
+
async def kill_old_chrome_process():
|
|
78
|
+
import subprocess
|
|
79
|
+
# Search for processes matching "hide-crash-restore-bubble"
|
|
80
|
+
process = subprocess.run(
|
|
81
|
+
["ps", "aux"], capture_output=True, text=True
|
|
82
|
+
)
|
|
83
|
+
lines = [
|
|
84
|
+
line for line in process.stdout.splitlines()
|
|
85
|
+
if "hide-crash-restore-bubble" in line and "grep" not in line
|
|
86
|
+
]
|
|
87
|
+
#Extract the PIDs (2nd element) and kill the processes
|
|
88
|
+
for line in lines:
|
|
89
|
+
parts = line.split()
|
|
90
|
+
pid = parts[1]
|
|
91
|
+
subprocess.run(["kill", "-9", pid])
|
|
92
|
+
|
|
93
|
+
async def launch_browser_in_independant_x11(self,temp_path):
|
|
94
|
+
xephyr_screen = RawScreen()
|
|
95
|
+
xephyr_number = xephyr_screen.launch_xephyr()
|
|
96
|
+
xephyr_screen.wait_for_display_ready()
|
|
97
|
+
self.dict_result = RawChrome(xephyr_number, self.browser_options,temp_path).start_in_thread()
|
|
98
|
+
config = self.no_driver_instance.Config(port=self.dict_result["port"], host="127.0.0.1")
|
|
99
|
+
config.user_data_dir = temp_path
|
|
100
|
+
self.no_driver_browser_instance = await self.no_driver_instance.start(config)
|
|
101
|
+
|
|
102
|
+
return FantomasNoDriverBrowser(self.no_driver_browser_instance, self.emulate_movement, self.show_cursor, self.emulate_keyboard)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
class FantomasNoDriverBrowser(Browser):
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def __init__(self, no_driver_browser_instance, emulate_movement, show_cursor,emulate_keyboard):
|
|
110
|
+
self.no_driver_browser_instance = no_driver_browser_instance
|
|
111
|
+
self.show_cursor = show_cursor
|
|
112
|
+
self.emulate_movement = emulate_movement
|
|
113
|
+
self.emulate_keyboard = emulate_keyboard
|
|
114
|
+
|
|
115
|
+
def __getattr__(self, name):
|
|
116
|
+
return getattr(self.no_driver_browser_instance, name)
|
|
117
|
+
|
|
118
|
+
async def get(self, page_url):
|
|
119
|
+
|
|
120
|
+
tab = await self.no_driver_browser_instance.get(page_url)
|
|
121
|
+
return FantomasNoDriverTab(tab, self.emulate_movement, self.show_cursor,self.emulate_keyboard)
|
|
122
|
+
|
|
123
|
+
async def open_new_tab(self,page_url):
|
|
124
|
+
tab = await self.no_driver_browser_instance.get(page_url,new_tab=True)
|
|
125
|
+
return FantomasNoDriverTab(tab, self.emulate_movement, self.show_cursor,self.emulate_keyboard)
|
|
126
|
+
|
|
127
|
+
async def open_new_window(self,page_url):
|
|
128
|
+
tab = await self.no_driver_browser_instance.get(page_url,new_window=True)
|
|
129
|
+
return FantomasNoDriverTab(tab, self.emulate_movement, self.show_cursor,self.emulate_keyboard)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
async def open_and_screenshot_image_to_b64(self,image_url):
|
|
133
|
+
secondary_tab = await self.open_new_tab(image_url)
|
|
134
|
+
element_to_screenshot = await secondary_tab.query_selector("img")
|
|
135
|
+
pos = await element_to_screenshot.get_position()
|
|
136
|
+
viewport = pos.to_viewport(1)
|
|
137
|
+
data = await element_to_screenshot._tab.send(
|
|
138
|
+
cdp.page.capture_screenshot(
|
|
139
|
+
"jpeg", clip=viewport, capture_beyond_viewport=True
|
|
140
|
+
)
|
|
141
|
+
)
|
|
142
|
+
await secondary_tab.close()
|
|
143
|
+
return data
|
|
144
|
+
|
|
145
|
+
#MonkeyPatching cookie injection
|
|
146
|
+
@property
|
|
147
|
+
def cookies(self):
|
|
148
|
+
if not self._cookies:
|
|
149
|
+
self._cookies = CookieJarMonkey(self)
|
|
150
|
+
return self._cookies
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
class CookieJarMonkey(CookieJar):
|
|
155
|
+
async def set_all(self, cookies):
|
|
156
|
+
connection = None
|
|
157
|
+
for tab in self._browser.tabs:
|
|
158
|
+
if tab.closed:
|
|
159
|
+
continue
|
|
160
|
+
connection = tab
|
|
161
|
+
break
|
|
162
|
+
else:
|
|
163
|
+
connection = self._browser.connection
|
|
164
|
+
await connection.send(cdp.storage.set_cookies(cookies))
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
class FantomasNoDriverTab(Tab):
|
|
168
|
+
|
|
169
|
+
def __init__(self,
|
|
170
|
+
no_driver_tab_instance: Tab,
|
|
171
|
+
emulate_movement: int,
|
|
172
|
+
show_cursor: int,
|
|
173
|
+
emulate_keyboard: int):
|
|
174
|
+
self.no_driver_tab_instance = no_driver_tab_instance
|
|
175
|
+
self.emulate_movement = emulate_movement
|
|
176
|
+
self.show_cursor = show_cursor
|
|
177
|
+
self.emulate_keyboard = emulate_keyboard
|
|
178
|
+
self.cursor_position = [0,0]
|
|
179
|
+
|
|
180
|
+
def __getattr__(self,
|
|
181
|
+
name: str):
|
|
182
|
+
return getattr(self.no_driver_tab_instance, name)
|
|
183
|
+
|
|
184
|
+
def __dir__(self):
|
|
185
|
+
return list(set(
|
|
186
|
+
dir(type(self)) + # attributs de la classe actuelle
|
|
187
|
+
dir(self) + # attributs de l’instance
|
|
188
|
+
dir(Tab) # attributs de l'objet "parent"
|
|
189
|
+
))
|
|
190
|
+
|
|
191
|
+
async def xclick_native(self,selector_list: list,
|
|
192
|
+
sleep_list: list,
|
|
193
|
+
proportion_list: list=[0.5,0.5]):
|
|
194
|
+
css_selector,css_selector_index = selector_list
|
|
195
|
+
sleep_before, sleep_after = sleep_list
|
|
196
|
+
await self.no_driver_tab_instance.wait_for(selector=css_selector)
|
|
197
|
+
|
|
198
|
+
if self.emulate_movement:
|
|
199
|
+
x,y,width,height = await get_coordinates_and_size(self,selector_list)
|
|
200
|
+
if proportion_list:
|
|
201
|
+
x = x + proportion_list[0]*width
|
|
202
|
+
y = y + proportion_list[1]*height
|
|
203
|
+
viewport_width, viewport_height = await get_viewport_size(self)
|
|
204
|
+
self.cursor_position = await self.xmove_native(selector_list)
|
|
205
|
+
|
|
206
|
+
await self.xsleep(sleep_before)
|
|
207
|
+
elements = await self.no_driver_tab_instance.select_all(css_selector)
|
|
208
|
+
element = elements[css_selector_index]
|
|
209
|
+
await element.click()
|
|
210
|
+
await self.xsleep(sleep_after)
|
|
211
|
+
|
|
212
|
+
async def xsend_native(self,
|
|
213
|
+
selector_list: list,
|
|
214
|
+
sleep_list: list,text=None):
|
|
215
|
+
css_selector,css_selector_index = selector_list
|
|
216
|
+
sleep_before,sleep_after = sleep_list
|
|
217
|
+
await self.no_driver_tab_instance.wait_for(selector=css_selector)
|
|
218
|
+
await self.xsleep(sleep_before)
|
|
219
|
+
targetted_elements = await self.select_all(css_selector)
|
|
220
|
+
targetted_element = targetted_elements[css_selector_index]
|
|
221
|
+
await self.xclick_native(selector_list,[0,0])
|
|
222
|
+
if self.emulate_keyboard:
|
|
223
|
+
await self._fill_native(targetted_element,text)
|
|
224
|
+
else:
|
|
225
|
+
await targetted_element.send_keys(text)
|
|
226
|
+
await self.xsleep(sleep_after)
|
|
227
|
+
|
|
228
|
+
async def xmove_native(self,
|
|
229
|
+
selector_list: list):
|
|
230
|
+
x,y,width,height = await get_coordinates_and_size(self,selector_list)
|
|
231
|
+
viewport_width, viewport_height = await get_viewport_size(self)
|
|
232
|
+
path = VirtualCursorPath().get_virtual_cursor_path(self.cursor_position,[x,y],viewport_width,viewport_height)
|
|
233
|
+
if self.show_cursor:
|
|
234
|
+
await cursor_illustration_show_native(self)
|
|
235
|
+
for i in range(len(path[0])):
|
|
236
|
+
await self.send(cdp.input_.dispatch_mouse_event("mouseMoved",path[0][i],path[1][i]))
|
|
237
|
+
if self.show_cursor:
|
|
238
|
+
await cursor_illustration_delete_native(self)
|
|
239
|
+
self.cursor_position = [x,y]
|
|
240
|
+
return [x,y]
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
async def xsleep(self,
|
|
244
|
+
sleeping_time: int,
|
|
245
|
+
factor:int=None):
|
|
246
|
+
if sleeping_time == 0:
|
|
247
|
+
randomized_sleeping_time = 0
|
|
248
|
+
elif sleeping_time == 0.5:
|
|
249
|
+
randomized_sleeping_time = random.uniform(0.15, 0.6)
|
|
250
|
+
else:
|
|
251
|
+
randomized_sleeping_time = random.uniform(sleeping_time-0.5, sleeping_time+0.5)
|
|
252
|
+
await self.no_driver_tab_instance.sleep(randomized_sleeping_time)
|
|
253
|
+
|
|
254
|
+
async def xwaiter(self,
|
|
255
|
+
css_selector: str,
|
|
256
|
+
timeout_delay: int,
|
|
257
|
+
sleep_list: list):
|
|
258
|
+
sleep_before,sleep_after = sleep_list
|
|
259
|
+
await self.xsleep(sleep_before)
|
|
260
|
+
await self.wait_for(selector=css_selector, timeout=timeout_delay)
|
|
261
|
+
await self.xsleep(sleep_after)
|
|
262
|
+
|
|
263
|
+
async def xdetector(self,
|
|
264
|
+
css_selector: str,
|
|
265
|
+
sleep_list: list):
|
|
266
|
+
sleep_before, sleep_after = sleep_list
|
|
267
|
+
await self.xsleep(sleep_before)
|
|
268
|
+
try:
|
|
269
|
+
css_selector_list = await self.select_all(css_selector, timeout=10)
|
|
270
|
+
await self.xsleep(sleep_after)
|
|
271
|
+
return bool(css_selector_list)
|
|
272
|
+
except Exception:
|
|
273
|
+
return False
|
|
274
|
+
|
|
275
|
+
async def xscrape_attribute_in_iframe(self,
|
|
276
|
+
iframe_number: int,
|
|
277
|
+
selector_list: list,
|
|
278
|
+
targetted_attribute: str):
|
|
279
|
+
css_selector,ordinal = selector_list #Parsing
|
|
280
|
+
full_document = await self.send(cdp.dom.get_document(-1, True))
|
|
281
|
+
iframes_list = get_iframes_of_document(full_document)
|
|
282
|
+
iframe = iframes_list[iframe_number]
|
|
283
|
+
iframe_node_id = iframe.node_id
|
|
284
|
+
targetted_elements_array = await self.send(cdp.dom.query_selector_all(iframe_node_id,css_selector))
|
|
285
|
+
targetted_element_node_id = targetted_elements_array[ordinal]
|
|
286
|
+
targetted_element_attributes = await self.send(cdp.dom.get_attributes(targetted_element_node_id))
|
|
287
|
+
index = targetted_element_attributes.index(targetted_attribute)
|
|
288
|
+
return targetted_element_attributes[index + 1]
|
|
289
|
+
|
|
290
|
+
async def xscrape_html_in_iframe(self,
|
|
291
|
+
iframe_number: int,
|
|
292
|
+
selector_list: list):
|
|
293
|
+
css_selector,ordinal = selector_list
|
|
294
|
+
full_document = await self.send(cdp.dom.get_document(-1, True))
|
|
295
|
+
iframes_list = get_iframes_of_document(full_document)
|
|
296
|
+
iframe = iframes_list[iframe_number]
|
|
297
|
+
iframe_node_id = iframe.node_id
|
|
298
|
+
targetted_elements_list = await self.send(cdp.dom.query_selector_all(iframe_node_id,css_selector))
|
|
299
|
+
targetted_element_node_id = targetted_elements_list[ordinal]
|
|
300
|
+
outer_html = await self.send(cdp.dom.get_outer_html(targetted_element_node_id))
|
|
301
|
+
return outer_html
|
|
302
|
+
|
|
303
|
+
async def xtemporary_zoom(self,
|
|
304
|
+
value_zoom: int):
|
|
305
|
+
command = "document.body.style.zoom="+str(value_zoom)
|
|
306
|
+
await self.send(cdp.runtime.evaluate(command))
|
|
307
|
+
await self.send(cdp.runtime.disable())
|
|
308
|
+
|
|
309
|
+
async def xinject_js(self,
|
|
310
|
+
js_command: str):
|
|
311
|
+
js_output = await self.send(cdp.runtime.evaluate(js_command,
|
|
312
|
+
return_by_value=True,allow_unsafe_eval_blocked_by_csp=True))
|
|
313
|
+
return js_output
|
|
314
|
+
|
|
315
|
+
async def xupload_file(self,
|
|
316
|
+
selector_list: list,
|
|
317
|
+
file_path: str):
|
|
318
|
+
css_selector,ordinal = selector_list
|
|
319
|
+
doc = await self.send(cdp.dom.get_document(-1, True))
|
|
320
|
+
page_node = doc.node_id
|
|
321
|
+
targetted_elements_list = await self.send(cdp.dom.query_selector_all(page_node,css_selector))
|
|
322
|
+
element = targetted_elements_list[ordinal]
|
|
323
|
+
await self.send(cdp.dom.set_file_input_files([file_path],element))
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
async def _fill_native(self, element,texte: str=None):
|
|
327
|
+
interval_min = random.uniform(0.01, 0.09)
|
|
328
|
+
interval_max = random.uniform(0.1, 0.7)
|
|
329
|
+
for i in texte:
|
|
330
|
+
sleeping_delay = random.uniform(interval_min, interval_max)
|
|
331
|
+
await self.xsleep(sleeping_delay)
|
|
332
|
+
await element.send_keys(i)
|
|
333
|
+
|
|
334
|
+
async def xselect_native(self,
|
|
335
|
+
selector_list: list,
|
|
336
|
+
sleep_list: list,
|
|
337
|
+
option_value: str = None,
|
|
338
|
+
option_text: str = None,
|
|
339
|
+
option_index: int = None):
|
|
340
|
+
css_selector, css_selector_index = selector_list
|
|
341
|
+
sleep_before, sleep_after = sleep_list
|
|
342
|
+
await self.no_driver_tab_instance.wait_for(selector=css_selector)
|
|
343
|
+
|
|
344
|
+
if self.emulate_movement:
|
|
345
|
+
self.cursor_position = await self.xmove_native(selector_list)
|
|
346
|
+
|
|
347
|
+
await self.xsleep(sleep_before)
|
|
348
|
+
|
|
349
|
+
doc = await self.send(cdp.dom.get_document(-1, True))
|
|
350
|
+
page_node_id = doc.node_id
|
|
351
|
+
select_elements = await self.send(cdp.dom.query_selector_all(page_node_id, css_selector))
|
|
352
|
+
select_node_id = select_elements[css_selector_index]
|
|
353
|
+
|
|
354
|
+
option_elements = await self.send(cdp.dom.query_selector_all(select_node_id, "option"))
|
|
355
|
+
|
|
356
|
+
target_option_node_id = None
|
|
357
|
+
|
|
358
|
+
if option_index is not None:
|
|
359
|
+
target_option_node_id = option_elements[option_index]
|
|
360
|
+
elif option_value is not None:
|
|
361
|
+
for option_node_id in option_elements:
|
|
362
|
+
attributes = await self.send(cdp.dom.get_attributes(option_node_id))
|
|
363
|
+
if "value" in attributes:
|
|
364
|
+
value_index = attributes.index("value")
|
|
365
|
+
if attributes[value_index + 1] == option_value:
|
|
366
|
+
target_option_node_id = option_node_id
|
|
367
|
+
break
|
|
368
|
+
elif option_text is not None:
|
|
369
|
+
for option_node_id in option_elements:
|
|
370
|
+
outer_html = await self.send(cdp.dom.get_outer_html(option_node_id))
|
|
371
|
+
import re
|
|
372
|
+
text_match = re.search(r'>([^<]*)<', outer_html)
|
|
373
|
+
if text_match and text_match.group(1).strip() == option_text:
|
|
374
|
+
target_option_node_id = option_node_id
|
|
375
|
+
break
|
|
376
|
+
else:
|
|
377
|
+
raise ValueError("Must provide one of: option_value, option_text, or option_index")
|
|
378
|
+
|
|
379
|
+
if target_option_node_id:
|
|
380
|
+
await self.send(cdp.dom.set_attribute_value(target_option_node_id, "selected", "selected"))
|
|
381
|
+
await self.send(cdp.dom.focus(select_node_id))
|
|
382
|
+
|
|
383
|
+
await self.xsleep(sleep_after)
|
|
384
|
+
|
|
385
|
+
#==================================================================#
|
|
386
|
+
# XDO METHODS
|
|
387
|
+
#==================================================================#
|
|
388
|
+
|
|
389
|
+
def xscroll_xdo(self,
|
|
390
|
+
x11_display: str,
|
|
391
|
+
times: int,
|
|
392
|
+
delay: int):
|
|
393
|
+
XdoToolActions.xscroll_xdo(x11_display,times,delay)
|
|
394
|
+
|
|
395
|
+
def xscroll_xdo_down(self,
|
|
396
|
+
x11_display: str,
|
|
397
|
+
times: int,
|
|
398
|
+
delay:int):
|
|
399
|
+
XdoToolActions.xscroll_xdo_down(x11_display,times,delay)
|
|
400
|
+
|
|
401
|
+
async def xclick_xdo(self,
|
|
402
|
+
selector_list: list,
|
|
403
|
+
sleep_list: list,
|
|
404
|
+
proportion_list: list=[0.5,0.5]):
|
|
405
|
+
css_selector,ordinal = selector_list
|
|
406
|
+
await self.no_driver_tab_instance.wait_for(selector=css_selector)
|
|
407
|
+
x,y, width,height = await get_coordinates_and_size(self,selector_list)
|
|
408
|
+
viewport_width, viewport_height = await get_viewport_size(self)
|
|
409
|
+
self.cursor_position = XdoToolActions(self.show_cursor).xclick_xdo(self.cursor_position,x,y,width,height,viewport_width,viewport_height,sleep_list,proportion_list)
|
|
410
|
+
|
|
411
|
+
async def xclick_xdo_x11(self,
|
|
412
|
+
x11_display,selector_list: list,
|
|
413
|
+
sleep_list: list,
|
|
414
|
+
proportion_list: list=[0.5,0.5]):
|
|
415
|
+
css_selector,ordinal = selector_list
|
|
416
|
+
await self.no_driver_tab_instance.wait_for(selector=css_selector)
|
|
417
|
+
x,y, width,height = await get_coordinates_and_size(self,selector_list)
|
|
418
|
+
viewport_width, viewport_height = await get_viewport_size(self)
|
|
419
|
+
self.cursor_position = XdoToolActions(self.show_cursor).xclick_xdo_x11(x11_display,self.cursor_position,x,y,width,height,viewport_width,viewport_height,sleep_list,proportion_list)
|
|
420
|
+
|
|
421
|
+
async def xclick_iframe_xdo(self,
|
|
422
|
+
iframe_number: int,
|
|
423
|
+
selector_list: list,
|
|
424
|
+
sleep_list: list,
|
|
425
|
+
proportion_list: list=[0.5,0.5]):
|
|
426
|
+
x,y,width,height = await get_coordinates_and_size_in_iframe(self,iframe_number,selector_list)
|
|
427
|
+
viewport_width, viewport_height = await get_viewport_size(self)
|
|
428
|
+
self.cursor_position = XdoToolActions(self.show_cursor).xclick_xdo(self.cursor_position,x,y,width,height,viewport_width,viewport_height,sleep_list,proportion_list)
|
|
429
|
+
|
|
430
|
+
async def xsend_xdo(self,
|
|
431
|
+
selector_list: list,
|
|
432
|
+
sleep_list: list,
|
|
433
|
+
text: str=None,
|
|
434
|
+
proportion_list: list=[0.5,0.5]):
|
|
435
|
+
css_selector,ordinal = selector_list
|
|
436
|
+
await self.no_driver_tab_instance.wait_for(selector=css_selector)
|
|
437
|
+
x,y, width,height = await get_coordinates_and_size(self,selector_list)
|
|
438
|
+
viewport_width, viewport_height = await get_viewport_size(self)
|
|
439
|
+
self.cursor_position = XdoToolActions(self.show_cursor).xsend_xdo(self.cursor_position,x,y,width,height,viewport_width,viewport_height,sleep_list,text,proportion_list)
|
|
440
|
+
|
|
441
|
+
async def xsend_xdo_x11(self,
|
|
442
|
+
x11_display: str,
|
|
443
|
+
selector_list: list,
|
|
444
|
+
sleep_list: list,
|
|
445
|
+
text=None,
|
|
446
|
+
proportion_list: list=[0.5,0.5]):
|
|
447
|
+
css_selector,ordinal = selector_list
|
|
448
|
+
await self.no_driver_tab_instance.wait_for(selector=css_selector)
|
|
449
|
+
x,y, width,height = await get_coordinates_and_size(self,selector_list)
|
|
450
|
+
viewport_width, viewport_height = await get_viewport_size(self)
|
|
451
|
+
self.cursor_position = XdoToolActions(self.show_cursor).xsend_xdo_x11(x11_display,self.cursor_position,x,y,width,height,viewport_width,viewport_height,sleep_list,text,proportion_list)
|
|
452
|
+
|
|
453
|
+
async def xsend_iframe_xdo(self, iframe_number: int, selector_list: list,sleep_list: list,text=None, proportion_list: list=[0.5,0.5]):
|
|
454
|
+
x,y,width,height = await get_coordinates_and_size_in_iframe(self,iframe_number,selector_list)
|
|
455
|
+
viewport_width, viewport_height = await get_viewport_size(self)
|
|
456
|
+
self.cursor_position = XdoToolActions(self.show_cursor).xsend_xdo(self.cursor_position,x,y,width,height,viewport_width,viewport_height,sleep_list,text,proportion_list)
|
|
457
|
+
|
|
458
|
+
def xsingle_send_xdo(self,key):
|
|
459
|
+
XdoToolActions(self.show_cursor).xsingle_send_xdo(key)
|
|
460
|
+
|
|
461
|
+
async def xmove_xdo(self,selector_list: list):
|
|
462
|
+
x,y,width,height = await get_coordinates_and_size(self,selector_list)
|
|
463
|
+
viewport_width, viewport_height = await get_viewport_size(self)
|
|
464
|
+
self.cursor_position = XdoToolActions(self.show_cursor).xmove_xdo(self.cursor_position,x,y,viewport_width,viewport_height)
|
|
465
|
+
|
|
466
|
+
async def xmove_xdo_x11(self,x11_display: str,selector_list: list):
|
|
467
|
+
x,y,width,height = await get_coordinates_and_size(self,selector_list)
|
|
468
|
+
viewport_width, viewport_height = await get_viewport_size(self)
|
|
469
|
+
self.cursor_position = XdoToolActions(self.show_cursor).xmove_xdo_x11(x11_display,self.cursor_position,x,y,viewport_width,viewport_height)
|
|
470
|
+
|
|
471
|
+
|
|
472
|
+
async def xmove_xdo_iframe(self,selector_list: list,iframe_number: int):
|
|
473
|
+
x,y,width,height = await get_coordinates_and_size_in_iframe(self,iframe_number,selector_list)
|
|
474
|
+
viewport_width, viewport_height = await get_viewport_size(self)
|
|
475
|
+
self.cursor_position = XdoToolActions(self.show_cursor).xmove_xdo(self.cursor_position,x,y,viewport_width,viewport_height)
|
fantomas/identity.py
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import re
|
|
2
|
+
import os
|
|
3
|
+
import random
|
|
4
|
+
from faker import Factory
|
|
5
|
+
from password_generator import PasswordGenerator
|
|
6
|
+
from .utils import get_value_or_default, load_config
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Identity:
|
|
10
|
+
|
|
11
|
+
def __init__(self, identity_params=None):
|
|
12
|
+
self.identity_params = identity_params if identity_params is not None else {}
|
|
13
|
+
self.enable_special_character_password = 1
|
|
14
|
+
self.language = 'fr_FR'
|
|
15
|
+
self.min_year = 18
|
|
16
|
+
self.max_year = 80
|
|
17
|
+
self.min_len_password = 12
|
|
18
|
+
self.max_len_password = 14
|
|
19
|
+
self.parse_identity_params()
|
|
20
|
+
|
|
21
|
+
def parse_identity_params(self):
|
|
22
|
+
self.identity_params = load_config(self.identity_params) if self.identity_params else {}
|
|
23
|
+
self.enable_special_character_password = get_value_or_default(self.identity_params.get("enable_special_character_password"), self.enable_special_character_password)
|
|
24
|
+
self.language = get_value_or_default(self.identity_params.get("language"), self.language)
|
|
25
|
+
self.min_year = get_value_or_default(self.identity_params.get("min_year"), self.min_year)
|
|
26
|
+
self.max_year = get_value_or_default(self.identity_params.get("max_year"), self.max_year)
|
|
27
|
+
self.min_len_password = get_value_or_default(self.identity_params.get("min_len_password"), self.min_len_password)
|
|
28
|
+
self.max_len_password = get_value_or_default(self.identity_params.get("max_len_password"), self.max_len_password)
|
|
29
|
+
|
|
30
|
+
def launch_identity_creation(self):
|
|
31
|
+
self.fake = Factory.create(self.language)
|
|
32
|
+
self.seed = int.from_bytes(os.urandom(4), 'little')
|
|
33
|
+
random.seed(self.seed)
|
|
34
|
+
self.fake.seed_instance(self.seed)
|
|
35
|
+
prenom = self.clean_name(self.fake.first_name())
|
|
36
|
+
nom = self.clean_name(self.fake.last_name())
|
|
37
|
+
birth = self.fake.date_of_birth(None, self.min_year, self.max_year)
|
|
38
|
+
birthday = birth.day
|
|
39
|
+
birthmonth = birth.month
|
|
40
|
+
birthyear = birth.year
|
|
41
|
+
postalcode = self.fake.postcode()
|
|
42
|
+
prefix = (prenom + nom + postalcode).lower()
|
|
43
|
+
password = self.create_password()
|
|
44
|
+
identity_data = {
|
|
45
|
+
'first_name': prenom,
|
|
46
|
+
'name': nom,
|
|
47
|
+
'alias': prefix,
|
|
48
|
+
'birth_day': birthday,
|
|
49
|
+
'birth_month': birthmonth,
|
|
50
|
+
'birth_year': birthyear,
|
|
51
|
+
'password': password
|
|
52
|
+
}
|
|
53
|
+
return identity_data
|
|
54
|
+
|
|
55
|
+
def create_password(self):
|
|
56
|
+
pwo = PasswordGenerator()
|
|
57
|
+
pwo.minlen = self.min_len_password
|
|
58
|
+
pwo.maxlen = self.max_len_password
|
|
59
|
+
password = pwo.generate()
|
|
60
|
+
if self.enable_special_character_password == 1:
|
|
61
|
+
password = re.sub(r'[^a-zA-Z0-9]', '', password)
|
|
62
|
+
return password
|
|
63
|
+
|
|
64
|
+
def clean_name(self,name_to_clean):
|
|
65
|
+
# Remove hyphens and apostrophes
|
|
66
|
+
name_to_clean = re.sub(r"[-' ]", '', name_to_clean)
|
|
67
|
+
# Remove accents from characters
|
|
68
|
+
name_to_clean = remove_accents(name_to_clean)
|
|
69
|
+
return name_to_clean
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def remove_accents(texte):
|
|
73
|
+
accents = {
|
|
74
|
+
'à': 'a', 'â': 'a', 'ä': 'a', 'á': 'a', 'ã': 'a', 'å': 'a',
|
|
75
|
+
'é': 'e', 'è': 'e', 'ê': 'e', 'ë': 'e',
|
|
76
|
+
'î': 'i', 'ï': 'i', 'ì': 'i', 'í': 'i',
|
|
77
|
+
'ô': 'o', 'ö': 'o', 'ò': 'o', 'ó': 'o', 'õ': 'o',
|
|
78
|
+
'ù': 'u', 'û': 'u', 'ü': 'u', 'ú': 'u',
|
|
79
|
+
'ý': 'y', 'ÿ': 'y',
|
|
80
|
+
'ç': 'c', 'ñ': 'n',
|
|
81
|
+
'À': 'A', 'Â': 'A', 'Ä': 'A', 'Á': 'A', 'Ã': 'A', 'Å': 'A',
|
|
82
|
+
'É': 'E', 'È': 'E', 'Ê': 'E', 'Ë': 'E',
|
|
83
|
+
'Î': 'I', 'Ï': 'I', 'Ì': 'I', 'Í': 'I',
|
|
84
|
+
'Ô': 'O', 'Ö': 'O', 'Ò': 'O', 'Ó': 'O', 'Õ': 'O',
|
|
85
|
+
'Ù': 'U', 'Û': 'U', 'Ü': 'U', 'Ú': 'U',
|
|
86
|
+
'Ý': 'Y',
|
|
87
|
+
'Ç': 'C', 'Ñ': 'N'
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return ''.join(accents.get(c, c) for c in texte)
|
|
91
|
+
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from nodriver import *
|
|
2
|
+
async def cursor_illustration_show_native(tab):
|
|
3
|
+
await tab.send(cdp.runtime.evaluate(expression="""
|
|
4
|
+
function enableCursor() {
|
|
5
|
+
var seleniumFollowerImg = document.createElement("img");
|
|
6
|
+
seleniumFollowerImg.setAttribute('src', 'data:image/png;base64,'
|
|
7
|
+
+ 'iVBORw0KGgoAAAANSUhEUgAAABQAAAAeCAQAAACGG/bgAAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAA'
|
|
8
|
+
+ 'HsYAAB7GAZEt8iwAAAAHdElNRQfgAwgMIwdxU/i7AAABZklEQVQ4y43TsU4UURSH8W+XmYwkS2I0'
|
|
9
|
+
+ '9CRKpKGhsvIJjG9giQmliHFZlkUIGnEF7KTiCagpsYHWhoTQaiUUxLixYZb5KAAZZhbunu7O/PKf'
|
|
10
|
+
+ 'e+fcA+/pqwb4DuximEqXhT4iI8dMpBWEsWsuGYdpZFttiLSSgTvhZ1W/SvfO1CvYdV1kPghV68a3'
|
|
11
|
+
+ '0zzUWZH5pBqEui7dnqlFmLoq0gxC1XfGZdoLal2kea8ahLoqKXNAJQBT2yJzwUTVt0bS6ANqy1ga'
|
|
12
|
+
+ 'VCEq/oVTtjji4hQVhhnlYBH4WIJV9vlkXLm+10R8oJb79Jl1j9UdazJRGpkrmNkSF9SOz2T71s7M'
|
|
13
|
+
+ 'SIfD2lmmfjGSRz3hK8l4w1P+bah/HJLN0sys2JSMZQB+jKo6KSc8vLlLn5ikzF4268Wg2+pPOWW6'
|
|
14
|
+
+ 'ONcpr3PrXy9VfS473M/D7H+TLmrqsXtOGctvxvMv2oVNP+Av0uHbzbxyJaywyUjx8TlnPY2YxqkD'
|
|
15
|
+
+ 'dAAAAABJRU5ErkJggg==');
|
|
16
|
+
seleniumFollowerImg.setAttribute('id', 'selenium_mouse_follower');
|
|
17
|
+
seleniumFollowerImg.setAttribute('style', 'position: absolute; z-index: 99999999999; pointer-events: none; width: 20px; height: 32px; left:-100px; top:-100px');
|
|
18
|
+
document.body.appendChild(seleniumFollowerImg);
|
|
19
|
+
document.onmousemove = function (e) {
|
|
20
|
+
document.getElementById("selenium_mouse_follower").style.left = e.pageX + 'px';
|
|
21
|
+
document.getElementById("selenium_mouse_follower").style.top = e.pageY + 'px';
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
enableCursor();"""))
|
|
26
|
+
|
|
27
|
+
async def cursor_illustration_delete_native(tab):
|
|
28
|
+
await tab.send(cdp.runtime.evaluate(expression="""function deleteCursor(){const imgElement = document.getElementById('selenium_mouse_follower');
|
|
29
|
+
if (imgElement) {imgElement.remove();
|
|
30
|
+
console.log('Image with id "selenium_mouse_follower" has been removed.');
|
|
31
|
+
} else {
|
|
32
|
+
console.warn('No element found with id "selenium_mouse_follower".');
|
|
33
|
+
};};
|
|
34
|
+
deleteCursor();
|
|
35
|
+
"""))
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from nodriver import *
|
|
2
|
+
from .IframeManager import *
|
|
3
|
+
|
|
4
|
+
async def get_viewport_size(tab):
|
|
5
|
+
dimensions = await tab.send(cdp.page.get_layout_metrics())
|
|
6
|
+
dimension = dimensions[1]
|
|
7
|
+
return [dimension.client_width, dimension.client_height]
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
async def get_coordinates_and_size(tab,selector_array):
|
|
11
|
+
selector_css,ordinal = selector_array
|
|
12
|
+
doc = await tab.send(cdp.dom.get_document(-1, True))
|
|
13
|
+
page_node = doc.node_id
|
|
14
|
+
targetted_elements_array = await tab.send(cdp.dom.query_selector_all(page_node,selector_css))
|
|
15
|
+
await tab.send(cdp.emulation.set_page_scale_factor(1)) #Pour pas d'erreur sur le box model
|
|
16
|
+
targetted_element_box = await tab.send(cdp.dom.get_box_model(targetted_elements_array[ordinal]))
|
|
17
|
+
x = int(targetted_element_box.content[0])
|
|
18
|
+
y = int(targetted_element_box.content[1])
|
|
19
|
+
width = int(targetted_element_box.width)
|
|
20
|
+
height = int(targetted_element_box.height)
|
|
21
|
+
return [x,y,width,height]
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
async def get_coordinates_and_size_in_iframe(tab,iframe_number,selector_array):
|
|
25
|
+
selector_css, ordinal = selector_array
|
|
26
|
+
document = await tab.send(cdp.dom.get_document(-1, True))
|
|
27
|
+
iframes_array = get_iframes_of_document(document)
|
|
28
|
+
iframe = iframes_array[iframe_number]
|
|
29
|
+
iframe_node_id = iframe.node_id
|
|
30
|
+
targetted_elements_array = await tab.send(cdp.dom.query_selector_all(iframe_node_id,selector_css))
|
|
31
|
+
targetted_element_node_id = targetted_elements_array[ordinal]
|
|
32
|
+
await tab.send(cdp.emulation.set_page_scale_factor(1)) #Pour pas d'erreur sur le box model
|
|
33
|
+
targetted_element_box = await tab.send(cdp.dom.get_box_model(targetted_element_node_id))
|
|
34
|
+
x = int(targetted_element_box.content[0])
|
|
35
|
+
y = int(targetted_element_box.content[1])
|
|
36
|
+
width = int(targetted_element_box.width)
|
|
37
|
+
height = int(targetted_element_box.height)
|
|
38
|
+
return [x,y,width,height]
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
def get_iframes_of_document(node):
|
|
2
|
+
document_nodes = []
|
|
3
|
+
if hasattr(node, 'content_document') and node.content_document is not None:
|
|
4
|
+
if hasattr(node.content_document, 'node_name') and node.content_document.node_name == '#document':
|
|
5
|
+
document_nodes.append(node.content_document)
|
|
6
|
+
document_nodes.extend(get_iframes_of_document(node.content_document)) #type: ignore
|
|
7
|
+
if hasattr(node, 'children') and node.children is not None:
|
|
8
|
+
for child in node.children:
|
|
9
|
+
document_nodes.extend(get_iframes_of_document(child)) #type: ignore
|
|
10
|
+
return document_nodes
|