formharvester 2.2.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.
- SeleniumBot.py +631 -0
- bot.py +882 -0
- dbc_api_python3/2x4.png +0 -0
- dbc_api_python3/banner.jpg +0 -0
- dbc_api_python3/deathbycaptcha.py +476 -0
- dbc_api_python3/new_funcaptcha.py +37 -0
- dbc_api_python3/new_recaptcha_coordinates.py +27 -0
- dbc_api_python3/new_recaptcha_image_group.py +38 -0
- dbc_api_python3/new_recaptcha_token_image.py +36 -0
- dbc_api_python3/new_recaptcha_token_v3.py +41 -0
- dbc_api_python3/readme.html +507 -0
- dbc_api_python3/test.jpg +0 -0
- dbc_api_python3/test2.jpg +0 -0
- formharvester-2.2.2.dist-info/METADATA +90 -0
- formharvester-2.2.2.dist-info/RECORD +18 -0
- formharvester-2.2.2.dist-info/WHEEL +4 -0
- formharvester-2.2.2.dist-info/licenses/LICENSE +21 -0
- utils.py +32 -0
SeleniumBot.py
ADDED
|
@@ -0,0 +1,631 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import os
|
|
3
|
+
import random
|
|
4
|
+
import re
|
|
5
|
+
import sys
|
|
6
|
+
import time
|
|
7
|
+
from urllib.parse import urljoin, parse_qs, urlparse
|
|
8
|
+
|
|
9
|
+
import requests
|
|
10
|
+
from bs4 import BeautifulSoup
|
|
11
|
+
from selenium import webdriver
|
|
12
|
+
from selenium.common.exceptions import (
|
|
13
|
+
NoSuchElementException,
|
|
14
|
+
)
|
|
15
|
+
from selenium.common.exceptions import TimeoutException
|
|
16
|
+
from selenium.webdriver.common.by import By
|
|
17
|
+
from selenium.webdriver.common.keys import Keys
|
|
18
|
+
from selenium.webdriver.support import expected_conditions as EC
|
|
19
|
+
from selenium.webdriver.support.ui import WebDriverWait, Select
|
|
20
|
+
import html
|
|
21
|
+
|
|
22
|
+
if getattr(sys, 'frozen', False):
|
|
23
|
+
BASE_DIR = os.path.dirname(sys.executable)
|
|
24
|
+
elif __file__:
|
|
25
|
+
BASE_DIR = os.path.dirname(os.path.realpath(__file__))
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class SeleniumBot:
|
|
29
|
+
driver = None
|
|
30
|
+
captcha_client = None
|
|
31
|
+
|
|
32
|
+
DEV_SETTINGS = None
|
|
33
|
+
COOKIES_PROFILE = None
|
|
34
|
+
HEADLESS = None
|
|
35
|
+
INCOGNITO = None
|
|
36
|
+
DISABLE_IMAGES = None
|
|
37
|
+
REMOTE_DEBUGGING = None
|
|
38
|
+
HIDE_EXTENSION = None
|
|
39
|
+
SINGLE_PROXY = None
|
|
40
|
+
PROXY_LIST = None
|
|
41
|
+
PROXY_AUTH = None
|
|
42
|
+
USERAGENT = None
|
|
43
|
+
FLASH = None
|
|
44
|
+
DATA_DIR = None
|
|
45
|
+
PROFILE = None
|
|
46
|
+
|
|
47
|
+
EXTENSIONS = []
|
|
48
|
+
|
|
49
|
+
WAIT = 99999
|
|
50
|
+
|
|
51
|
+
TIMEOUT = 5
|
|
52
|
+
MAX_SLEEP = 5
|
|
53
|
+
|
|
54
|
+
MIN_RAND = 0.64
|
|
55
|
+
MAX_RAND = 1.27
|
|
56
|
+
MIN_RAND_LONG = 4.78
|
|
57
|
+
MAX_RAND_LONG = 11.1
|
|
58
|
+
|
|
59
|
+
NUM_MOUSE_MOVES = 10
|
|
60
|
+
|
|
61
|
+
crawl = True
|
|
62
|
+
|
|
63
|
+
def get(self, page, pre_sleep=0, sleep=0, timeout=False, check=False):
|
|
64
|
+
|
|
65
|
+
if not self.crawl:
|
|
66
|
+
return
|
|
67
|
+
|
|
68
|
+
if check:
|
|
69
|
+
try:
|
|
70
|
+
requests.get(page, timeout=8)
|
|
71
|
+
except:
|
|
72
|
+
return
|
|
73
|
+
|
|
74
|
+
if timeout:
|
|
75
|
+
self.driver.set_page_load_timeout(timeout)
|
|
76
|
+
|
|
77
|
+
time.sleep(pre_sleep)
|
|
78
|
+
try:
|
|
79
|
+
self.driver.get(page)
|
|
80
|
+
time.sleep(sleep)
|
|
81
|
+
if timeout:
|
|
82
|
+
self.driver.set_page_load_timeout(-1)
|
|
83
|
+
return True
|
|
84
|
+
except Exception as e:
|
|
85
|
+
print(e)
|
|
86
|
+
if timeout:
|
|
87
|
+
self.driver.set_page_load_timeout(-1)
|
|
88
|
+
return False
|
|
89
|
+
|
|
90
|
+
def get_wait(self, url, selector, wait=9999):
|
|
91
|
+
self.get(url)
|
|
92
|
+
return self.wait_show_element(selector, wait=wait)
|
|
93
|
+
|
|
94
|
+
def reload(self):
|
|
95
|
+
self.driver.refresh()
|
|
96
|
+
|
|
97
|
+
def close(self):
|
|
98
|
+
if self.COOKIES_PROFILE:
|
|
99
|
+
self.save_cookies()
|
|
100
|
+
try:
|
|
101
|
+
self.driver.quit()
|
|
102
|
+
except:
|
|
103
|
+
pass
|
|
104
|
+
|
|
105
|
+
def script(self, script, *args):
|
|
106
|
+
return self.driver.execute_script(script, *args)
|
|
107
|
+
|
|
108
|
+
def css(self, selector, node=None, getall=False, attr=None,
|
|
109
|
+
wait=None, wait_for=None,
|
|
110
|
+
):
|
|
111
|
+
|
|
112
|
+
if wait:
|
|
113
|
+
w = self.wait_show_element(selector, wait=wait)
|
|
114
|
+
if not w:
|
|
115
|
+
return None
|
|
116
|
+
if wait_for:
|
|
117
|
+
w = self.wait_for_element(selector, wait=wait_for)
|
|
118
|
+
if not w:
|
|
119
|
+
return None
|
|
120
|
+
|
|
121
|
+
if getall:
|
|
122
|
+
el = self.get_elements_from(node if node else self.driver, selector)
|
|
123
|
+
else:
|
|
124
|
+
el = self.get_element_from(node if node else self.driver, selector)
|
|
125
|
+
|
|
126
|
+
if attr and el:
|
|
127
|
+
el = self.extract_attributes(el, attr)
|
|
128
|
+
|
|
129
|
+
return el
|
|
130
|
+
|
|
131
|
+
def xpath(self, selector, node=None, getall=False, attr=None, wait=None):
|
|
132
|
+
if wait:
|
|
133
|
+
w = self.wait_show_element(selector, xpath=True, wait=wait)
|
|
134
|
+
if not w:
|
|
135
|
+
return None
|
|
136
|
+
|
|
137
|
+
if getall:
|
|
138
|
+
el = self.get_elements_from(node if node else self.driver, selector, xpath=True)
|
|
139
|
+
else:
|
|
140
|
+
el = self.get_element_from(node if node else self.driver, selector, xpath=True)
|
|
141
|
+
|
|
142
|
+
if attr and el:
|
|
143
|
+
el = self.extract_attributes(el, attr)
|
|
144
|
+
|
|
145
|
+
return el
|
|
146
|
+
|
|
147
|
+
def get_attr(self, el, attr):
|
|
148
|
+
if type(attr) == list:
|
|
149
|
+
output = []
|
|
150
|
+
for a in attr:
|
|
151
|
+
if a == 'text':
|
|
152
|
+
output.append(el.text)
|
|
153
|
+
else:
|
|
154
|
+
output.append(el.get_attribute(a))
|
|
155
|
+
else:
|
|
156
|
+
if attr == 'text':
|
|
157
|
+
output = el.text
|
|
158
|
+
else:
|
|
159
|
+
output = el.get_attribute(attr)
|
|
160
|
+
return output
|
|
161
|
+
|
|
162
|
+
def extract_attributes(self, el, attr):
|
|
163
|
+
if type(el) == list:
|
|
164
|
+
return [self.get_attr(i, attr) for i in el]
|
|
165
|
+
else:
|
|
166
|
+
return self.get_attr(el, attr)
|
|
167
|
+
|
|
168
|
+
def contains_text(self, text):
|
|
169
|
+
try:
|
|
170
|
+
return self.driver.find_element(By.XPATH, f'//*[contains(text(), "{text}")]')
|
|
171
|
+
except NoSuchElementException:
|
|
172
|
+
return None
|
|
173
|
+
|
|
174
|
+
def contains_regex(self, regex):
|
|
175
|
+
page_text = self.css('body').text
|
|
176
|
+
if re.findall(rf'{regex}', page_text):
|
|
177
|
+
return True
|
|
178
|
+
else:
|
|
179
|
+
return False
|
|
180
|
+
|
|
181
|
+
def submit_form(self, element):
|
|
182
|
+
try:
|
|
183
|
+
element.submit()
|
|
184
|
+
return True
|
|
185
|
+
except TimeoutException:
|
|
186
|
+
return False
|
|
187
|
+
|
|
188
|
+
def wait_page_load(self):
|
|
189
|
+
while True:
|
|
190
|
+
page_state = self.script(
|
|
191
|
+
'return document.readyState;')
|
|
192
|
+
self.driver.implicitly_wait(1)
|
|
193
|
+
if page_state == 'complete':
|
|
194
|
+
break
|
|
195
|
+
return
|
|
196
|
+
|
|
197
|
+
def wait_for_text(self, text, wait=99999):
|
|
198
|
+
try:
|
|
199
|
+
wait = WebDriverWait(self.driver, wait)
|
|
200
|
+
element = wait.until(EC.presence_of_element_located((By.XPATH, f'//*[contains(text(), "{text}")]')))
|
|
201
|
+
return element
|
|
202
|
+
except:
|
|
203
|
+
return None
|
|
204
|
+
|
|
205
|
+
def wait_for_regex(self, regex):
|
|
206
|
+
while True:
|
|
207
|
+
if self.contains_regex(regex):
|
|
208
|
+
return True
|
|
209
|
+
time.sleep(.5)
|
|
210
|
+
|
|
211
|
+
def wait_for_element(self, selector, xpath=False, wait=99999):
|
|
212
|
+
try:
|
|
213
|
+
wait = WebDriverWait(self.driver, wait)
|
|
214
|
+
if xpath:
|
|
215
|
+
element = wait.until(EC.presence_of_element_located((By.XPATH, selector)))
|
|
216
|
+
else:
|
|
217
|
+
element = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, selector)))
|
|
218
|
+
return element
|
|
219
|
+
except:
|
|
220
|
+
return None
|
|
221
|
+
|
|
222
|
+
def wait_show_element(self, selector, xpath=False, wait=99999):
|
|
223
|
+
try:
|
|
224
|
+
wait = WebDriverWait(self.driver, wait)
|
|
225
|
+
if xpath:
|
|
226
|
+
element = wait.until(EC.visibility_of_element_located((By.XPATH, selector)))
|
|
227
|
+
else:
|
|
228
|
+
element = wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, selector)))
|
|
229
|
+
return element
|
|
230
|
+
except:
|
|
231
|
+
return None
|
|
232
|
+
|
|
233
|
+
def wait_hide_element(self, selector, wait):
|
|
234
|
+
try:
|
|
235
|
+
wait = WebDriverWait(self.driver, wait)
|
|
236
|
+
element = wait.until(EC.invisibility_of_element_located((By.CSS_SELECTOR, selector)))
|
|
237
|
+
return element
|
|
238
|
+
except:
|
|
239
|
+
return None
|
|
240
|
+
|
|
241
|
+
def wait_click_element(self, selector, wait):
|
|
242
|
+
try:
|
|
243
|
+
wait = WebDriverWait(self.driver, wait)
|
|
244
|
+
element = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, selector)))
|
|
245
|
+
return element
|
|
246
|
+
except:
|
|
247
|
+
return None
|
|
248
|
+
|
|
249
|
+
def element_is_present(self, selector):
|
|
250
|
+
try:
|
|
251
|
+
self.driver.find_element(By.CSS_SELECTOR, selector)
|
|
252
|
+
return True
|
|
253
|
+
except NoSuchElementException:
|
|
254
|
+
return False
|
|
255
|
+
|
|
256
|
+
def verify_element_present(self, selector):
|
|
257
|
+
if not self.element_is_present(selector):
|
|
258
|
+
raise Exception('Element %s not found' % selector)
|
|
259
|
+
|
|
260
|
+
def get_element_from(self, fromObject, selector, xpath=False):
|
|
261
|
+
try:
|
|
262
|
+
if xpath:
|
|
263
|
+
return fromObject.find_element(By.XPATH, selector)
|
|
264
|
+
else:
|
|
265
|
+
return fromObject.find_element(By.CSS_SELECTOR, selector)
|
|
266
|
+
except NoSuchElementException:
|
|
267
|
+
return None
|
|
268
|
+
|
|
269
|
+
def get_elements_from(self, fromObject, selector, xpath=False):
|
|
270
|
+
try:
|
|
271
|
+
if xpath:
|
|
272
|
+
return fromObject.find_elements(By.XPATH, selector)
|
|
273
|
+
else:
|
|
274
|
+
return fromObject.find_elements(By.CSS_SELECTOR, selector)
|
|
275
|
+
except NoSuchElementException:
|
|
276
|
+
return []
|
|
277
|
+
|
|
278
|
+
def get_element_from_value(self, fromObject, selector):
|
|
279
|
+
element = self.get_element_from(fromObject, selector)
|
|
280
|
+
if element:
|
|
281
|
+
return element.text
|
|
282
|
+
return None
|
|
283
|
+
|
|
284
|
+
def get_element_value(self, selector):
|
|
285
|
+
element = self.css(selector)
|
|
286
|
+
if element:
|
|
287
|
+
return element.text
|
|
288
|
+
return None
|
|
289
|
+
|
|
290
|
+
def get_element_from_attribute(self, fromObject, selector, attribute):
|
|
291
|
+
element = self.get_element_from(fromObject, selector)
|
|
292
|
+
if element:
|
|
293
|
+
return element.get_attribute(attribute)
|
|
294
|
+
return None
|
|
295
|
+
|
|
296
|
+
def get_element_attribute(self, selector, attribute):
|
|
297
|
+
element = self.css(selector)
|
|
298
|
+
if element:
|
|
299
|
+
return element.get_attribute(attribute)
|
|
300
|
+
return None
|
|
301
|
+
|
|
302
|
+
def get_parent_levels(self, node, levels):
|
|
303
|
+
path = '..'
|
|
304
|
+
if levels > 1:
|
|
305
|
+
for i in range(1, levels):
|
|
306
|
+
path = path + '/..'
|
|
307
|
+
return node.find_element(By.XPATH, path)
|
|
308
|
+
|
|
309
|
+
def get_parent_node(self, node):
|
|
310
|
+
return node.find_element(By.XPATH, '..')
|
|
311
|
+
|
|
312
|
+
def get_child_nodes(self, node):
|
|
313
|
+
return node.find_elements(By.XPATH, './*')
|
|
314
|
+
|
|
315
|
+
def write(self, field, text,
|
|
316
|
+
css=False,
|
|
317
|
+
xpath=False,
|
|
318
|
+
name=False,
|
|
319
|
+
wait=False,
|
|
320
|
+
clear=False,
|
|
321
|
+
human=False,
|
|
322
|
+
submit=False,
|
|
323
|
+
):
|
|
324
|
+
|
|
325
|
+
if wait:
|
|
326
|
+
self.wait_show_element(field, wait=self.WAIT, xpath=xpath)
|
|
327
|
+
|
|
328
|
+
if css:
|
|
329
|
+
field = self.css(field)
|
|
330
|
+
elif xpath:
|
|
331
|
+
field = self.xpath(field)
|
|
332
|
+
elif name:
|
|
333
|
+
field = self.driver.find_element(By.NAME, field)
|
|
334
|
+
|
|
335
|
+
if clear:
|
|
336
|
+
if human:
|
|
337
|
+
while field.get_attribute('value') != '':
|
|
338
|
+
field.send_keys(Keys.BACKSPACE)
|
|
339
|
+
time.sleep(random.uniform(.05, .1))
|
|
340
|
+
self.random_sleep()
|
|
341
|
+
else:
|
|
342
|
+
field.clear()
|
|
343
|
+
|
|
344
|
+
if human:
|
|
345
|
+
for letter in text:
|
|
346
|
+
field.send_keys(letter)
|
|
347
|
+
time.sleep(random.uniform(.05, .2))
|
|
348
|
+
else:
|
|
349
|
+
field.send_keys(text)
|
|
350
|
+
|
|
351
|
+
if submit:
|
|
352
|
+
try:
|
|
353
|
+
field.send_keys(text)
|
|
354
|
+
except:
|
|
355
|
+
self.driver.execute_script(f'arguments[0].value = "{text}"', field)
|
|
356
|
+
|
|
357
|
+
return field
|
|
358
|
+
|
|
359
|
+
def press_key(self, key):
|
|
360
|
+
webdriver.ActionChains(self.driver).send_keys(key).perform()
|
|
361
|
+
|
|
362
|
+
def press_enter(self, field_object):
|
|
363
|
+
field_object.send_keys(Keys.RETURN)
|
|
364
|
+
return field_object
|
|
365
|
+
|
|
366
|
+
def click(self,
|
|
367
|
+
element,
|
|
368
|
+
wait=False,
|
|
369
|
+
css=False,
|
|
370
|
+
xpath=False,
|
|
371
|
+
js_click=False,
|
|
372
|
+
sleep=False,
|
|
373
|
+
double=False):
|
|
374
|
+
|
|
375
|
+
if wait:
|
|
376
|
+
w = self.wait_show_element(element, wait=wait, xpath=xpath)
|
|
377
|
+
if not w:
|
|
378
|
+
return None
|
|
379
|
+
|
|
380
|
+
if sleep:
|
|
381
|
+
time.sleep(sleep)
|
|
382
|
+
|
|
383
|
+
if css:
|
|
384
|
+
element = self.css(element)
|
|
385
|
+
elif xpath:
|
|
386
|
+
element = self.xpath(element)
|
|
387
|
+
|
|
388
|
+
if double:
|
|
389
|
+
rng = 2
|
|
390
|
+
else:
|
|
391
|
+
rng = 1
|
|
392
|
+
|
|
393
|
+
for _ in range(rng):
|
|
394
|
+
try:
|
|
395
|
+
# use Selenium's built in click function
|
|
396
|
+
actions = webdriver.ActionChains(self.driver)
|
|
397
|
+
actions.move_to_element(element)
|
|
398
|
+
actions.click(element)
|
|
399
|
+
actions.perform()
|
|
400
|
+
return element
|
|
401
|
+
except:
|
|
402
|
+
try:
|
|
403
|
+
script = ("var viewPortHeight = Math.max("
|
|
404
|
+
"document.documentElement.clientHeight, window.innerHeight || 0);"
|
|
405
|
+
"var elementTop = arguments[0].getBoundingClientRect().top;"
|
|
406
|
+
"window.scrollBy(0, elementTop-(viewPortHeight/2));")
|
|
407
|
+
self.driver.execute_script(script) # parent = the webdriver
|
|
408
|
+
element.click()
|
|
409
|
+
except:
|
|
410
|
+
# try `execute_script` as a last resort
|
|
411
|
+
# print("attempting last ditch effort for click, `execute_script`")
|
|
412
|
+
self.script("arguments[0].click();", element)
|
|
413
|
+
return element
|
|
414
|
+
|
|
415
|
+
def select_checkbox(self, selector, name, deselect=False):
|
|
416
|
+
found_checkbox = False
|
|
417
|
+
checkboxes = self.css(selector, getall=True)
|
|
418
|
+
for checkbox in checkboxes:
|
|
419
|
+
if checkbox.get_attribute('name') == name:
|
|
420
|
+
found_checkbox = True
|
|
421
|
+
if not deselect and not checkbox.is_selected():
|
|
422
|
+
checkbox.click()
|
|
423
|
+
if deselect and checkbox.is_selected():
|
|
424
|
+
checkbox.click()
|
|
425
|
+
if not found_checkbox:
|
|
426
|
+
raise Exception('Checkbox %s not found.' % name)
|
|
427
|
+
|
|
428
|
+
def select_option(self, selector, value):
|
|
429
|
+
found_option = False
|
|
430
|
+
options = self.css(selector, getall=True)
|
|
431
|
+
for option in options:
|
|
432
|
+
if option.get_attribute('value') == str(value):
|
|
433
|
+
found_option = True
|
|
434
|
+
option.click()
|
|
435
|
+
if not found_option:
|
|
436
|
+
raise Exception('Option %s not found' % (value))
|
|
437
|
+
|
|
438
|
+
def select_dropdown(self, value, xpath=False):
|
|
439
|
+
if xpath:
|
|
440
|
+
elem = Select(self.driver.find_element(By.XPATH, value))
|
|
441
|
+
else:
|
|
442
|
+
elem = Select(self.driver.find_element(By.CSS_SELECTOR, value))
|
|
443
|
+
return elem
|
|
444
|
+
|
|
445
|
+
def get_selected_option(self, selector):
|
|
446
|
+
options = self.css(selector)
|
|
447
|
+
for option in options:
|
|
448
|
+
if option.is_selected():
|
|
449
|
+
return option.get_attribute('value')
|
|
450
|
+
|
|
451
|
+
def is_option_selected(self, selector, value):
|
|
452
|
+
options = self.css(selector)
|
|
453
|
+
for option in options:
|
|
454
|
+
if option.is_selected() != (value == option.get_attribute('value')):
|
|
455
|
+
print(option.get_attribute('value'))
|
|
456
|
+
return False
|
|
457
|
+
return True
|
|
458
|
+
|
|
459
|
+
def drag_drop(self, drag, drop):
|
|
460
|
+
drag_item = self.css(drag)
|
|
461
|
+
target_item = self.css(drop)
|
|
462
|
+
action_chains = webdriver.ActionChains(self.driver)
|
|
463
|
+
action_chains.drag_and_drop(drag_item, target_item).perform()
|
|
464
|
+
|
|
465
|
+
def move_to_element(self, element):
|
|
466
|
+
self.driver.execute_script("return arguments[0].scrollIntoView();", element)
|
|
467
|
+
actions = webdriver.ActionChains(self.driver)
|
|
468
|
+
actions.move_to_element(element)
|
|
469
|
+
actions.perform()
|
|
470
|
+
|
|
471
|
+
def check_title(self, title):
|
|
472
|
+
return self.driver.title == title
|
|
473
|
+
|
|
474
|
+
def save_screenshot(self, path=f"{str(int(time.time()))}.png"):
|
|
475
|
+
self.driver.save_screenshot(path)
|
|
476
|
+
|
|
477
|
+
def scroll_up(self, y=100):
|
|
478
|
+
scroll = self.driver.execute_script('return document.documentElement.scrollTop')
|
|
479
|
+
self.driver.execute_script(f'scrollTo(0, {scroll - y})')
|
|
480
|
+
|
|
481
|
+
def scroll_down(self, y=400):
|
|
482
|
+
scroll = self.driver.execute_script('return document.documentElement.scrollTop')
|
|
483
|
+
self.driver.execute_script(f'scrollTo(0, {scroll + y})')
|
|
484
|
+
|
|
485
|
+
def log(self, screenshot=False, error=None):
|
|
486
|
+
try:
|
|
487
|
+
timestamp = str(int(time.time()))
|
|
488
|
+
filename = os.path.join('log', timestamp)
|
|
489
|
+
output = ''
|
|
490
|
+
|
|
491
|
+
if not os.path.exists('log'):
|
|
492
|
+
os.mkdir('log')
|
|
493
|
+
|
|
494
|
+
if screenshot:
|
|
495
|
+
self.save_screenshot(f'{filename}.png')
|
|
496
|
+
|
|
497
|
+
output += str(self.driver.current_url) + '\n\n'
|
|
498
|
+
|
|
499
|
+
if error:
|
|
500
|
+
output += f'{error}\n\n'
|
|
501
|
+
|
|
502
|
+
output += str(self.driver.page_source)
|
|
503
|
+
|
|
504
|
+
soup = BeautifulSoup(self.driver.page_source, 'html.parser')
|
|
505
|
+
output += str(soup.prettify()) + '\n\n'
|
|
506
|
+
|
|
507
|
+
with open(f'{filename}.log', 'w', encoding='utf8') as f:
|
|
508
|
+
f.write(output)
|
|
509
|
+
|
|
510
|
+
except Exception as e:
|
|
511
|
+
print(e)
|
|
512
|
+
|
|
513
|
+
def highlight(self, element,
|
|
514
|
+
css=False):
|
|
515
|
+
if css:
|
|
516
|
+
element = self.css(element)
|
|
517
|
+
self.driver.execute_script("arguments[0].style.border='6px groove green'", element)
|
|
518
|
+
|
|
519
|
+
def check_captcha(self,
|
|
520
|
+
recaptcha=False,
|
|
521
|
+
image=False):
|
|
522
|
+
|
|
523
|
+
if image:
|
|
524
|
+
# Captcha 1 (image)
|
|
525
|
+
src = self.xpath('//img[contains(@class, "captcha") or contains(@src, "captcha")]',
|
|
526
|
+
attr='src')
|
|
527
|
+
if src:
|
|
528
|
+
return urljoin(self.driver.current_url, src)
|
|
529
|
+
|
|
530
|
+
if recaptcha:
|
|
531
|
+
# Captcha 1
|
|
532
|
+
site_key = self.css('.g-recaptcha', attr='data-sitekey')
|
|
533
|
+
if site_key:
|
|
534
|
+
return site_key
|
|
535
|
+
|
|
536
|
+
# Captcha 2
|
|
537
|
+
site_key = self.xpath('//*[contains(@class, "recaptcha") and @data-sitekey]', attr='data-sitekey')
|
|
538
|
+
if site_key:
|
|
539
|
+
return site_key
|
|
540
|
+
|
|
541
|
+
# Captcha 3
|
|
542
|
+
src = self.css('.grecaptcha-logo>iframe', attr='src')
|
|
543
|
+
if src:
|
|
544
|
+
src = html.unescape(src)
|
|
545
|
+
site_key = parse_qs(urlparse(src).query)['k'][0]
|
|
546
|
+
return site_key
|
|
547
|
+
|
|
548
|
+
# Captcha 4
|
|
549
|
+
src = self.xpath('//iframe[contains(@src, "recaptcha") and contains(@src, "k=")]',
|
|
550
|
+
attr='src')
|
|
551
|
+
if src:
|
|
552
|
+
src = html.unescape(src)
|
|
553
|
+
site_key = parse_qs(urlparse(src).query)['k'][0]
|
|
554
|
+
return site_key
|
|
555
|
+
return None
|
|
556
|
+
|
|
557
|
+
def solve_captcha(self, site_key, recaptcha=False, image=False):
|
|
558
|
+
if image:
|
|
559
|
+
captcha = self.captcha_client.decode(site_key)
|
|
560
|
+
if captcha:
|
|
561
|
+
return captcha.get('text')
|
|
562
|
+
|
|
563
|
+
if recaptcha:
|
|
564
|
+
payload = {
|
|
565
|
+
'googlekey': site_key,
|
|
566
|
+
'pageurl': self.driver.current_url,
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
captcha = self.captcha_client.decode(type=4, token_params=json.dumps(payload))
|
|
570
|
+
if captcha:
|
|
571
|
+
print(captcha)
|
|
572
|
+
captcha_response = self.css('#g-recaptcha-response')
|
|
573
|
+
if captcha_response:
|
|
574
|
+
self.script(f'''
|
|
575
|
+
arguments[0].innerHTML='{captcha['text']}'
|
|
576
|
+
''', captcha_response)
|
|
577
|
+
else:
|
|
578
|
+
captcha_response = self.xpath(
|
|
579
|
+
'//input[contains(@class, "captcha") or contains(@name, "captcha") or contains(@id, "captcha")]'
|
|
580
|
+
)
|
|
581
|
+
if captcha_response:
|
|
582
|
+
self.script(f'''
|
|
583
|
+
arguments[0].innerHTML='{captcha['text']}'
|
|
584
|
+
''', captcha_response)
|
|
585
|
+
return True
|
|
586
|
+
|
|
587
|
+
def check_solve_captchas(self, recaptcha=False, image=False):
|
|
588
|
+
|
|
589
|
+
if self.captcha_client:
|
|
590
|
+
|
|
591
|
+
if recaptcha:
|
|
592
|
+
site_key = self.check_captcha(recaptcha=True)
|
|
593
|
+
if site_key:
|
|
594
|
+
return self.solve_captcha(
|
|
595
|
+
site_key,
|
|
596
|
+
recaptcha=True,
|
|
597
|
+
)
|
|
598
|
+
else:
|
|
599
|
+
return None
|
|
600
|
+
|
|
601
|
+
if image:
|
|
602
|
+
img_url = self.check_captcha(image=True)
|
|
603
|
+
if img_url:
|
|
604
|
+
self.download_file(img_url, 'captcha.png')
|
|
605
|
+
return self.solve_captcha(
|
|
606
|
+
'captcha.png',
|
|
607
|
+
image=True,
|
|
608
|
+
)
|
|
609
|
+
else:
|
|
610
|
+
return None
|
|
611
|
+
|
|
612
|
+
@staticmethod
|
|
613
|
+
def download_file(url, path=BASE_DIR):
|
|
614
|
+
with open(path, 'wb') as f:
|
|
615
|
+
r = requests.get(url)
|
|
616
|
+
for chunk in r.iter_content(1024):
|
|
617
|
+
f.write(chunk)
|
|
618
|
+
|
|
619
|
+
def random_sleep(self, *args, **kwargs):
|
|
620
|
+
|
|
621
|
+
if kwargs.get('long'):
|
|
622
|
+
time.sleep(random.uniform(self.MIN_RAND_LONG, self.MAX_RAND_LONG))
|
|
623
|
+
|
|
624
|
+
elif len(args) == 1:
|
|
625
|
+
time.sleep(random.uniform(1, args[0]))
|
|
626
|
+
|
|
627
|
+
elif len(args) == 2:
|
|
628
|
+
time.sleep(random.uniform(args[0], args[1]))
|
|
629
|
+
|
|
630
|
+
else:
|
|
631
|
+
time.sleep(random.uniform(self.MIN_RAND, self.MAX_RAND))
|