dublib 0.1.0__tar.gz → 0.2.0__tar.gz
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.
- {dublib-0.1.0/src/dublib.egg-info → dublib-0.2.0}/PKG-INFO +3 -1
- {dublib-0.1.0 → dublib-0.2.0}/pyproject.toml +2 -2
- {dublib-0.1.0 → dublib-0.2.0}/src/dublib/Exceptions/WebRequestor.py +1 -1
- dublib-0.2.0/src/dublib/WebRequestor.py +820 -0
- {dublib-0.1.0 → dublib-0.2.0/src/dublib.egg-info}/PKG-INFO +3 -1
- {dublib-0.1.0 → dublib-0.2.0}/src/dublib.egg-info/requires.txt +2 -0
- dublib-0.1.0/src/dublib/WebRequestor.py +0 -440
- {dublib-0.1.0 → dublib-0.2.0}/LICENSE +0 -0
- {dublib-0.1.0 → dublib-0.2.0}/README.md +0 -0
- {dublib-0.1.0 → dublib-0.2.0}/setup.cfg +0 -0
- {dublib-0.1.0 → dublib-0.2.0}/src/dublib/Exceptions/StyledPrinter.py +0 -0
- {dublib-0.1.0 → dublib-0.2.0}/src/dublib/Exceptions/Terminalyzer.py +0 -0
- {dublib-0.1.0 → dublib-0.2.0}/src/dublib/Exceptions/__init__.py +0 -0
- {dublib-0.1.0 → dublib-0.2.0}/src/dublib/Methods.py +0 -0
- {dublib-0.1.0 → dublib-0.2.0}/src/dublib/StyledPrinter.py +0 -0
- {dublib-0.1.0 → dublib-0.2.0}/src/dublib/Terminalyzer.py +0 -0
- {dublib-0.1.0 → dublib-0.2.0}/src/dublib/__init__.py +0 -0
- {dublib-0.1.0 → dublib-0.2.0}/src/dublib.egg-info/SOURCES.txt +0 -0
- {dublib-0.1.0 → dublib-0.2.0}/src/dublib.egg-info/dependency_links.txt +0 -0
- {dublib-0.1.0 → dublib-0.2.0}/src/dublib.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: dublib
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: Коллекция модулей от DUB1401.
|
|
5
5
|
Author-email: DUB1401 <vlad.milosta@outlook.com>
|
|
6
6
|
License: This is free and unencumbered software released into the public domain.
|
|
@@ -44,6 +44,8 @@ Requires-Python: >=3.10
|
|
|
44
44
|
Description-Content-Type: text/markdown
|
|
45
45
|
License-File: LICENSE
|
|
46
46
|
Requires-Dist: fake_useragent
|
|
47
|
+
Requires-Dist: httpx
|
|
48
|
+
Requires-Dist: httpx[http2]
|
|
47
49
|
Requires-Dist: requests
|
|
48
50
|
|
|
49
51
|
# dublib
|
|
@@ -3,7 +3,7 @@ requires = ["setuptools", "cython"]
|
|
|
3
3
|
|
|
4
4
|
[project]
|
|
5
5
|
name = "dublib"
|
|
6
|
-
version = "0.
|
|
6
|
+
version = "0.2.0"
|
|
7
7
|
description = "Коллекция модулей от DUB1401."
|
|
8
8
|
authors = [
|
|
9
9
|
{name = "DUB1401", email="vlad.milosta@outlook.com"}
|
|
@@ -11,7 +11,7 @@ authors = [
|
|
|
11
11
|
readme = "README.md"
|
|
12
12
|
license = {file = "LICENSE"}
|
|
13
13
|
requires-python = ">=3.10"
|
|
14
|
-
dependencies = ["fake_useragent", "requests"]
|
|
14
|
+
dependencies = ["fake_useragent", "httpx", "httpx[http2]", "requests"]
|
|
15
15
|
classifiers = [
|
|
16
16
|
"Development Status :: 4 - Beta",
|
|
17
17
|
"License :: OSI Approved :: The Unlicense (Unlicense)",
|
|
@@ -10,7 +10,7 @@ class ConfigRequired(Exception):
|
|
|
10
10
|
"""
|
|
11
11
|
|
|
12
12
|
# Добавление данных в сообщение об ошибке.
|
|
13
|
-
self.__Message = "
|
|
13
|
+
self.__Message = "Any requests library config required."
|
|
14
14
|
# Обеспечение доступа к оригиналу наследованного свойства.
|
|
15
15
|
super().__init__(self.__Message)
|
|
16
16
|
|
|
@@ -0,0 +1,820 @@
|
|
|
1
|
+
from fake_useragent import UserAgent as UserAgentGenerator
|
|
2
|
+
from dublib.Exceptions.WebRequestor import *
|
|
3
|
+
|
|
4
|
+
import importlib
|
|
5
|
+
import requests
|
|
6
|
+
import logging
|
|
7
|
+
import random
|
|
8
|
+
import httpx
|
|
9
|
+
import enum
|
|
10
|
+
|
|
11
|
+
#==========================================================================================#
|
|
12
|
+
# >>>>> ВСПОМОГАТЕЛЬНЫЕ ТИПЫ ДАННЫХ <<<<< #
|
|
13
|
+
#==========================================================================================#
|
|
14
|
+
|
|
15
|
+
class Browsers(enum.Enum):
|
|
16
|
+
"""
|
|
17
|
+
Перечисление типов поддерживаемых браузеров.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
Chrome = "Google Chrome"
|
|
21
|
+
#Firefox = "Mozilla Firefox"
|
|
22
|
+
#Edge = "Microsoft Edge"
|
|
23
|
+
|
|
24
|
+
class Protocols(enum.Enum):
|
|
25
|
+
"""
|
|
26
|
+
Перечисление типов протоколов.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
FTP = "ftp"
|
|
30
|
+
HTTP = "http"
|
|
31
|
+
HTTPS = "https"
|
|
32
|
+
SOCKS = "socks"
|
|
33
|
+
|
|
34
|
+
class HttpxConfig:
|
|
35
|
+
"""
|
|
36
|
+
Конфигурация библиотеки httpx.
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
#==========================================================================================#
|
|
40
|
+
# >>>>> СВОЙСТВА <<<<< #
|
|
41
|
+
#==========================================================================================#
|
|
42
|
+
|
|
43
|
+
@property
|
|
44
|
+
def headers(self) -> dict:
|
|
45
|
+
return self.__Headers.copy()
|
|
46
|
+
|
|
47
|
+
@property
|
|
48
|
+
def http2(self) -> bool:
|
|
49
|
+
return self.__HTTP2
|
|
50
|
+
|
|
51
|
+
@property
|
|
52
|
+
def redirecting(self) -> bool:
|
|
53
|
+
return self.__Redirecting
|
|
54
|
+
|
|
55
|
+
#==========================================================================================#
|
|
56
|
+
# >>>>> МЕТОДЫ <<<<< #
|
|
57
|
+
#==========================================================================================#
|
|
58
|
+
|
|
59
|
+
def __init__(self, AutoUserAgent: bool = True):
|
|
60
|
+
"""
|
|
61
|
+
Конфигурация библиотеки httpx.
|
|
62
|
+
AutoUserAgent – переключает автоматическую генерацию заголовка User-Agent.
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
#---> Генерация динамических свойств.
|
|
66
|
+
#==========================================================================================#
|
|
67
|
+
# Заголовки запросов.
|
|
68
|
+
self.__Headers = dict()
|
|
69
|
+
# Состояние: выполнять ли переадресацию.
|
|
70
|
+
self.__Redirecting = True
|
|
71
|
+
# Состояние: использовать ли HTTP2.0.
|
|
72
|
+
self.__HTTP2 = True
|
|
73
|
+
|
|
74
|
+
# Если указано, сгенерировать заголовок User-Agent.
|
|
75
|
+
if AutoUserAgent == True: self.__Headers = {"User-Agent": UserAgentGenerator().chrome}
|
|
76
|
+
|
|
77
|
+
def addHeader(self, Key: str, Value: int | str):
|
|
78
|
+
"""
|
|
79
|
+
Добавляет пользовательский заголовок запроса.
|
|
80
|
+
Key – ключ заголовка;
|
|
81
|
+
Value – значение заголовка.
|
|
82
|
+
"""
|
|
83
|
+
|
|
84
|
+
# Запись заголовка.
|
|
85
|
+
self.__Headers[Key] = Value
|
|
86
|
+
|
|
87
|
+
def enableHTTP2(self, Value: bool):
|
|
88
|
+
"""
|
|
89
|
+
Переключает использование протокола HTTP2.0.
|
|
90
|
+
Value – статус использования протокола.
|
|
91
|
+
"""
|
|
92
|
+
|
|
93
|
+
self.__HTTP2 = Value
|
|
94
|
+
|
|
95
|
+
def enableRedirecting(self, Value: bool):
|
|
96
|
+
"""
|
|
97
|
+
Переключает автоматическое перенаправление HTTP.
|
|
98
|
+
Value – статус перенаправления.
|
|
99
|
+
"""
|
|
100
|
+
|
|
101
|
+
self.__Redirecting = Value
|
|
102
|
+
|
|
103
|
+
def setReferer(self, Referer: str):
|
|
104
|
+
"""
|
|
105
|
+
Задаёт пользовательское значение заголовка Referer.
|
|
106
|
+
Referer – новое значение заголовка.
|
|
107
|
+
"""
|
|
108
|
+
|
|
109
|
+
self.__Headers["Referer"] = Referer
|
|
110
|
+
|
|
111
|
+
def setUserAgent(self, UserAgent: str):
|
|
112
|
+
"""
|
|
113
|
+
Задаёт пользовательское значение заголовка User-Agent.
|
|
114
|
+
UserAgent – новое значение заголовка.
|
|
115
|
+
"""
|
|
116
|
+
|
|
117
|
+
self.__Headers["User-Agent"] = UserAgent
|
|
118
|
+
|
|
119
|
+
class RequestsConfig:
|
|
120
|
+
"""
|
|
121
|
+
Конфигурация библиотеки requests.
|
|
122
|
+
"""
|
|
123
|
+
|
|
124
|
+
#==========================================================================================#
|
|
125
|
+
# >>>>> СВОЙСТВА <<<<< #
|
|
126
|
+
#==========================================================================================#
|
|
127
|
+
|
|
128
|
+
@property
|
|
129
|
+
def headers(self) -> dict:
|
|
130
|
+
return self.__Headers.copy()
|
|
131
|
+
|
|
132
|
+
@property
|
|
133
|
+
def redirecting(self) -> bool:
|
|
134
|
+
return self.__Redirecting
|
|
135
|
+
|
|
136
|
+
#==========================================================================================#
|
|
137
|
+
# >>>>> МЕТОДЫ <<<<< #
|
|
138
|
+
#==========================================================================================#
|
|
139
|
+
|
|
140
|
+
def __init__(self, AutoUserAgent: bool = True):
|
|
141
|
+
"""
|
|
142
|
+
Конфигурация библиотеки requests.
|
|
143
|
+
AutoUserAgent – переключает автоматическую генерацию заголовка User-Agent.
|
|
144
|
+
"""
|
|
145
|
+
|
|
146
|
+
#---> Генерация динамических свойств.
|
|
147
|
+
#==========================================================================================#
|
|
148
|
+
# Заголовки запросов.
|
|
149
|
+
self.__Headers = dict()
|
|
150
|
+
# Состояние: выполнять ли переадресацию.
|
|
151
|
+
self.__Redirecting = True
|
|
152
|
+
|
|
153
|
+
# Если указано, сгенерировать заголовок User-Agent.
|
|
154
|
+
if AutoUserAgent == True: self.__Headers = {"User-Agent": UserAgentGenerator().chrome}
|
|
155
|
+
|
|
156
|
+
def addHeader(self, Key: str, Value: int | str):
|
|
157
|
+
"""
|
|
158
|
+
Добавляет пользовательский заголовок запроса.
|
|
159
|
+
Key – ключ заголовка;
|
|
160
|
+
Value – значение заголовка.
|
|
161
|
+
"""
|
|
162
|
+
|
|
163
|
+
# Запись заголовка.
|
|
164
|
+
self.__Headers[Key] = Value
|
|
165
|
+
|
|
166
|
+
def enableRedirecting(self, Value: bool):
|
|
167
|
+
"""
|
|
168
|
+
Переключает автоматическое перенаправление HTTP.
|
|
169
|
+
Value – статус перенаправления.
|
|
170
|
+
"""
|
|
171
|
+
|
|
172
|
+
self.__Redirecting = Value
|
|
173
|
+
|
|
174
|
+
def setReferer(self, Referer: str):
|
|
175
|
+
"""
|
|
176
|
+
Задаёт пользовательское значение заголовка Referer.
|
|
177
|
+
Referer – новое значение заголовка.
|
|
178
|
+
"""
|
|
179
|
+
|
|
180
|
+
self.__Headers["Referer"] = Referer
|
|
181
|
+
|
|
182
|
+
def setUserAgent(self, UserAgent: str):
|
|
183
|
+
"""
|
|
184
|
+
Задаёт пользовательское значение заголовка User-Agent.
|
|
185
|
+
UserAgent – новое значение заголовка.
|
|
186
|
+
"""
|
|
187
|
+
|
|
188
|
+
self.__Headers["User-Agent"] = UserAgent
|
|
189
|
+
|
|
190
|
+
class SeleniumConfig:
|
|
191
|
+
"""
|
|
192
|
+
Конфигурация библиотеки Selenium.
|
|
193
|
+
"""
|
|
194
|
+
|
|
195
|
+
def __init__(
|
|
196
|
+
self,
|
|
197
|
+
BrowserType: Browsers = Browsers.Chrome,
|
|
198
|
+
Headless: bool = False,
|
|
199
|
+
PageLoadTimeout: int = 75,
|
|
200
|
+
ScriptTimeout: int = 75,
|
|
201
|
+
WindowWidth: int = 1920,
|
|
202
|
+
WindowHeight: int = 1080
|
|
203
|
+
):
|
|
204
|
+
"""
|
|
205
|
+
Конфигурация библиотеки Selenium.
|
|
206
|
+
"""
|
|
207
|
+
|
|
208
|
+
#---> Генерация динамических свойств.
|
|
209
|
+
#==========================================================================================#
|
|
210
|
+
# Тип используемого браузера.
|
|
211
|
+
self.BrowserType = BrowserType
|
|
212
|
+
# Состояние: активен ли безрабочный режим.
|
|
213
|
+
self.Headless = Headless
|
|
214
|
+
# Тайм-аут загрузки страницы.
|
|
215
|
+
self.PageLoadTimeout = PageLoadTimeout
|
|
216
|
+
# Тайм-аут выполнения JavaScript.
|
|
217
|
+
self.ScriptTimeout = ScriptTimeout
|
|
218
|
+
# Ширина окна.
|
|
219
|
+
self.WindowWidth = WindowWidth
|
|
220
|
+
# Высота окна.
|
|
221
|
+
self.WindowHeight = WindowHeight
|
|
222
|
+
|
|
223
|
+
def setBrowserType(self, BrowserType: Browsers):
|
|
224
|
+
"""
|
|
225
|
+
Задаёт используемый браузер.
|
|
226
|
+
BrowserType – браузер.
|
|
227
|
+
"""
|
|
228
|
+
|
|
229
|
+
self.BrowserType = BrowserType
|
|
230
|
+
|
|
231
|
+
def setHeadless(self, Headless: bool):
|
|
232
|
+
"""
|
|
233
|
+
Переключает отображение окна браузера.
|
|
234
|
+
Headless – состояние отображение окна браузера.
|
|
235
|
+
"""
|
|
236
|
+
|
|
237
|
+
self.Headless = Headless
|
|
238
|
+
|
|
239
|
+
def setPageLoadTimeout(self, PageLoadTimeout: int):
|
|
240
|
+
"""
|
|
241
|
+
Задаёт тайм-аут загрузки страницы.
|
|
242
|
+
PageLoadTimeout – тайм-аут загрузки страницы в секундах.
|
|
243
|
+
"""
|
|
244
|
+
|
|
245
|
+
self.PageLoadTimeout = PageLoadTimeout
|
|
246
|
+
|
|
247
|
+
def setScriptTimeout(self, ScriptTimeout: int):
|
|
248
|
+
"""
|
|
249
|
+
Задаёт тайм-аут выполнения JavaScript.
|
|
250
|
+
PageLoadTimeout – тайм-аут выполнения JavaScript в секундах.
|
|
251
|
+
"""
|
|
252
|
+
|
|
253
|
+
self.ScriptTimeout = ScriptTimeout
|
|
254
|
+
|
|
255
|
+
def setWindowSize(self, Width: int, Height: int):
|
|
256
|
+
"""
|
|
257
|
+
Задаёт размер окна браузера.
|
|
258
|
+
Width – ширина окна в пикселях;
|
|
259
|
+
Height – высота окна в пикселях.
|
|
260
|
+
"""
|
|
261
|
+
|
|
262
|
+
self.WindowWidth = Width
|
|
263
|
+
self.WindowHeight = Height
|
|
264
|
+
|
|
265
|
+
class WebResponse:
|
|
266
|
+
"""
|
|
267
|
+
Эмуляция структуры ответа библиотеки requests.
|
|
268
|
+
"""
|
|
269
|
+
|
|
270
|
+
#==========================================================================================#
|
|
271
|
+
# >>>>> СТАТИЧЕСКИЕ СВОЙСТВА <<<<< #
|
|
272
|
+
#==========================================================================================#
|
|
273
|
+
|
|
274
|
+
# Статус ответа.
|
|
275
|
+
status_code = None
|
|
276
|
+
# Бинарное представление ответа.
|
|
277
|
+
content = None
|
|
278
|
+
# Текстовое представление ответа.
|
|
279
|
+
text = None
|
|
280
|
+
|
|
281
|
+
#==========================================================================================#
|
|
282
|
+
# >>>>> МЕТОДЫ <<<<< #
|
|
283
|
+
#==========================================================================================#
|
|
284
|
+
|
|
285
|
+
# Конструктор.
|
|
286
|
+
def __init__(self):
|
|
287
|
+
"""
|
|
288
|
+
Эмуляция структуры ответа библиотеки requests.
|
|
289
|
+
"""
|
|
290
|
+
|
|
291
|
+
#---> Генерация динамических свойств.
|
|
292
|
+
#==========================================================================================#
|
|
293
|
+
# Статус ответа.
|
|
294
|
+
status_code = None
|
|
295
|
+
# Бинарное представление ответа.
|
|
296
|
+
content = None
|
|
297
|
+
# Текстовое представление ответа.
|
|
298
|
+
text = None
|
|
299
|
+
|
|
300
|
+
#==========================================================================================#
|
|
301
|
+
# >>>>> ОСНОВНОЙ КЛАСС <<<<< #
|
|
302
|
+
#==========================================================================================#
|
|
303
|
+
|
|
304
|
+
class WebRequestor:
|
|
305
|
+
"""
|
|
306
|
+
Запросчик HTML кода веб-страниц.
|
|
307
|
+
"""
|
|
308
|
+
|
|
309
|
+
#==========================================================================================#
|
|
310
|
+
# >>>>> ВСПОМОГАТЕЛЬНЫЕ МЕТОДЫ <<<<< #
|
|
311
|
+
#==========================================================================================#
|
|
312
|
+
|
|
313
|
+
def __CheckConfig(self):
|
|
314
|
+
"""
|
|
315
|
+
Выбрасывает исключение при отсутствии конфигурации.
|
|
316
|
+
"""
|
|
317
|
+
|
|
318
|
+
# Если конфигурация не задана, выбросить исключение.
|
|
319
|
+
if self.__Config == None: raise ConfigRequired()
|
|
320
|
+
|
|
321
|
+
def __GetProxy(self) -> dict | None:
|
|
322
|
+
"""
|
|
323
|
+
Возвращает объект прокси для запроса.
|
|
324
|
+
"""
|
|
325
|
+
|
|
326
|
+
# Объект прокси.
|
|
327
|
+
Proxy = None
|
|
328
|
+
|
|
329
|
+
# Если задан хотя бы один прокси..
|
|
330
|
+
if len(self.__Proxies) > 0:
|
|
331
|
+
# Случайный выбор прокси.
|
|
332
|
+
Proxy = random.choice(self.__Proxies)
|
|
333
|
+
# Данные авторизации.
|
|
334
|
+
Auth = ""
|
|
335
|
+
# Если указаны логин и пароль, составить авторизационные данные.
|
|
336
|
+
if Proxy["login"] != None and Proxy["password"] != None: Auth = Proxy["login"] + ":" + Proxy["password"] + "@"
|
|
337
|
+
|
|
338
|
+
# Если задана конфигурация requests.
|
|
339
|
+
if type(self.__Config) == RequestsConfig:
|
|
340
|
+
# Создание объекта прокси.
|
|
341
|
+
Proxy = {
|
|
342
|
+
Proxy["protocol"]: Proxy["protocol"].replace("https", "http") + "://" + Auth + Proxy["host"] + ":" + Proxy["port"]
|
|
343
|
+
}
|
|
344
|
+
print(Proxy)
|
|
345
|
+
|
|
346
|
+
# Если задана конфигурация httpx.
|
|
347
|
+
if type(self.__Config) == HttpxConfig:
|
|
348
|
+
# Создание объекта прокси.
|
|
349
|
+
Proxy = {
|
|
350
|
+
Proxy["protocol"] + "://": Proxy["protocol"].replace("https", "http") + "://" + Auth + Proxy["host"] + ":" + Proxy["port"]
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
return Proxy
|
|
354
|
+
|
|
355
|
+
def __InitializeChrome(self):
|
|
356
|
+
"""
|
|
357
|
+
Инициализирует браузер Google Chrome.
|
|
358
|
+
"""
|
|
359
|
+
|
|
360
|
+
# Закрытие браузера.
|
|
361
|
+
self.close()
|
|
362
|
+
# Опции веб-браузера.
|
|
363
|
+
ChromeOptions = self.Options.Options()
|
|
364
|
+
# Установка опций.
|
|
365
|
+
ChromeOptions.add_argument("--no-sandbox")
|
|
366
|
+
ChromeOptions.add_argument("--disable-dev-shm-usage")
|
|
367
|
+
ChromeOptions.add_argument("--disable-gpu")
|
|
368
|
+
ChromeOptions.add_experimental_option("excludeSwitches", ["enable-logging"])
|
|
369
|
+
# При отключённом режиме отладки скрыть окно браузера.
|
|
370
|
+
if self.__Config.Headless == True: ChromeOptions.add_argument("--headless=new")
|
|
371
|
+
# Инициализация браузера.
|
|
372
|
+
self.__Browser = self.selenium.webdriver.Chrome(service = self.Service.Service(self.ChromeDriverManager.ChromeDriverManager().install()), options = ChromeOptions)
|
|
373
|
+
# Установка размера окна браузера на FullHD для корректной работы сайтов.
|
|
374
|
+
self.__Browser.set_window_size(self.__Config.WindowWidth, self.__Config.WindowHeight)
|
|
375
|
+
# Установка максимального времени загрузки страницы и выполнения скрипта.
|
|
376
|
+
self.__Browser.set_page_load_timeout(self.__Config.PageLoadTimeout)
|
|
377
|
+
self.__Browser.set_script_timeout(self.__Config.ScriptTimeout)
|
|
378
|
+
|
|
379
|
+
#==========================================================================================#
|
|
380
|
+
# >>>>> МЕТОДЫ ЗАПРОСОВ <<<<< #
|
|
381
|
+
#==========================================================================================#
|
|
382
|
+
|
|
383
|
+
def __httpx_GET(self, URL: str, Params: dict | None = None, Headers: dict | None = None, Cookies: dict | None = None) -> httpx.Response:
|
|
384
|
+
"""
|
|
385
|
+
Отправляет GET запрос через библиотеку httpx.
|
|
386
|
+
URL – адрес запроса;
|
|
387
|
+
Params – словарь параметров запроса;
|
|
388
|
+
Headers – словарь заголовков;
|
|
389
|
+
Cookies – словарь куков.
|
|
390
|
+
"""
|
|
391
|
+
|
|
392
|
+
# Если переданы заголовки.
|
|
393
|
+
if Headers != None:
|
|
394
|
+
# Объединение словарей заголовков из конфигурации и аргументов.
|
|
395
|
+
Headers = self.__Config.headers | Headers
|
|
396
|
+
|
|
397
|
+
else:
|
|
398
|
+
# Установка словаря заголовков из конфигурации.
|
|
399
|
+
Headers = self.__Config.headers
|
|
400
|
+
|
|
401
|
+
# Ответ.
|
|
402
|
+
Response = self.__Client.get(URL, params = Params, headers = Headers, cookies = Cookies, follow_redirects = self.__Config.redirecting)
|
|
403
|
+
|
|
404
|
+
return Response
|
|
405
|
+
|
|
406
|
+
def __httpx_POST(self, URL: str, Params: dict | None = None, Headers: dict | None = None, Cookies: dict | None = None, Data: any = None, JSON: dict | None = None) -> httpx.Response:
|
|
407
|
+
"""
|
|
408
|
+
Отправляет POST запрос через библиотеку httpx.
|
|
409
|
+
URL – адрес запроса;
|
|
410
|
+
Params – словарь параметров запроса;
|
|
411
|
+
Headers – словарь заголовков;
|
|
412
|
+
Data – данные запроса;
|
|
413
|
+
Cookies – словарь куков.
|
|
414
|
+
"""
|
|
415
|
+
|
|
416
|
+
# Если переданы заголовки.
|
|
417
|
+
if Headers != None:
|
|
418
|
+
# Объединение словарей заголовков из конфигурации и аргументов.
|
|
419
|
+
Headers = self.__Config.headers | Headers
|
|
420
|
+
|
|
421
|
+
else:
|
|
422
|
+
# Установка словаря заголовков из конфигурации.
|
|
423
|
+
Headers = self.__Config.headers
|
|
424
|
+
|
|
425
|
+
# Ответ.
|
|
426
|
+
Response = self.__Client.post(URL, params = Params, headers = Headers, cookies = Cookies, data = Data, json = JSON, follow_redirects = self.__Config.redirecting)
|
|
427
|
+
|
|
428
|
+
return Response
|
|
429
|
+
|
|
430
|
+
def __requests_GET(self, URL: str, Params: dict | None = None, Headers: dict | None = None, Cookies: dict | None = None) -> requests.Response:
|
|
431
|
+
"""
|
|
432
|
+
Отправляет GET запрос через библиотеку requests.
|
|
433
|
+
URL – адрес запроса;
|
|
434
|
+
Params – словарь параметров запроса;
|
|
435
|
+
Headers – словарь заголовков;
|
|
436
|
+
Cookies – словарь куков.
|
|
437
|
+
"""
|
|
438
|
+
|
|
439
|
+
# Если переданы заголовки.
|
|
440
|
+
if Headers != None:
|
|
441
|
+
# Объединение словарей заголовков из конфигурации и аргументов.
|
|
442
|
+
Headers = self.__Config.headers | Headers
|
|
443
|
+
|
|
444
|
+
else:
|
|
445
|
+
# Установка словаря заголовков из конфигурации.
|
|
446
|
+
Headers = self.__Config.headers
|
|
447
|
+
|
|
448
|
+
# Ответ.
|
|
449
|
+
Response = self.__Session.get(URL, params = Params, headers = Headers, cookies = Cookies, proxies = self.__GetProxy(), allow_redirects = self.__Config.redirecting)
|
|
450
|
+
|
|
451
|
+
return Response
|
|
452
|
+
|
|
453
|
+
def __requests_POST(self, URL: str, Params: dict | None = None, Headers: dict | None = None, Cookies: dict | None = None, Data: any = None, JSON: dict | None = None) -> requests.Response:
|
|
454
|
+
"""
|
|
455
|
+
Отправляет POST запрос через библиотеку requests.
|
|
456
|
+
URL – адрес запроса;
|
|
457
|
+
Params – словарь параметров запроса;
|
|
458
|
+
Headers – словарь заголовков;
|
|
459
|
+
Cookies – словарь куков;
|
|
460
|
+
Data – данные запроса;
|
|
461
|
+
JSON – тело запроса.
|
|
462
|
+
"""
|
|
463
|
+
|
|
464
|
+
# Если переданы заголовки.
|
|
465
|
+
if Headers != None:
|
|
466
|
+
# Объединение словарей заголовков из конфигурации и аргументов.
|
|
467
|
+
Headers = self.__Config.headers | Headers
|
|
468
|
+
|
|
469
|
+
else:
|
|
470
|
+
# Установка словаря заголовков из конфигурации.
|
|
471
|
+
Headers = self.__Config.headers
|
|
472
|
+
|
|
473
|
+
# Ответ.
|
|
474
|
+
Response = self.__Session.post(URL, params = Params, headers = Headers, cookies = Cookies, data = Data, json = JSON, proxies = self.__GetProxy(), allow_redirects = self.__Config.redirecting)
|
|
475
|
+
|
|
476
|
+
return Response
|
|
477
|
+
|
|
478
|
+
def __selenium_LOAD(self, URL: str) -> WebResponse:
|
|
479
|
+
"""
|
|
480
|
+
Запрашивает страницу при помощи библиотеки Selenium.
|
|
481
|
+
"""
|
|
482
|
+
|
|
483
|
+
# Ответ.
|
|
484
|
+
Response = WebResponse()
|
|
485
|
+
|
|
486
|
+
try:
|
|
487
|
+
# Запрос страницы.
|
|
488
|
+
self.__Browser.get(URL)
|
|
489
|
+
|
|
490
|
+
except self.TimeoutException.TimeoutException:
|
|
491
|
+
# Установка свойств ответа.
|
|
492
|
+
Response.status_code = 408
|
|
493
|
+
|
|
494
|
+
except Exception:
|
|
495
|
+
# Установка свойств ответа.
|
|
496
|
+
Response.status_code = 499
|
|
497
|
+
|
|
498
|
+
else:
|
|
499
|
+
# Установка свойств ответа.
|
|
500
|
+
Response.status_code = 200
|
|
501
|
+
Response.text = self.__Browser.execute_script("return document.body.innerHTML;")
|
|
502
|
+
Response.content = bytes(Response.text)
|
|
503
|
+
|
|
504
|
+
return Response
|
|
505
|
+
|
|
506
|
+
def __init__(self, Logging: bool = False):
|
|
507
|
+
"""
|
|
508
|
+
Запросчик HTML кода веб-страниц.
|
|
509
|
+
Logging – переключает ведение логов при помощи стандартного модуля logging.
|
|
510
|
+
"""
|
|
511
|
+
|
|
512
|
+
#---> Генерация динамических свойств.
|
|
513
|
+
#==========================================================================================#
|
|
514
|
+
# Конфигурация.
|
|
515
|
+
self.__Config = None
|
|
516
|
+
# Сессия запросов httpx.
|
|
517
|
+
self.__Session = None
|
|
518
|
+
# Клиент запросов httpx.
|
|
519
|
+
self.__Client = None
|
|
520
|
+
# Экземпляр веб-браузера Selenium.
|
|
521
|
+
self.__Browser = None
|
|
522
|
+
# Состояние: вести ли логи.
|
|
523
|
+
self.__Logging = Logging
|
|
524
|
+
# Список прокси.
|
|
525
|
+
self.__Proxies = list()
|
|
526
|
+
|
|
527
|
+
#==========================================================================================#
|
|
528
|
+
# >>>>> ОБЩИЕ МЕТОДЫ <<<<< #
|
|
529
|
+
#==========================================================================================#
|
|
530
|
+
|
|
531
|
+
def close(self):
|
|
532
|
+
"""
|
|
533
|
+
Закрывает запросчик.
|
|
534
|
+
"""
|
|
535
|
+
|
|
536
|
+
# Если задана конфигурация Selenium.
|
|
537
|
+
if type(self.__Config) == SeleniumConfig:
|
|
538
|
+
|
|
539
|
+
try:
|
|
540
|
+
# Закрытие браузера.
|
|
541
|
+
self.__Browser.close()
|
|
542
|
+
self.__Browser.quit()
|
|
543
|
+
# Обнуление экземпляра.
|
|
544
|
+
self.__Browser = None
|
|
545
|
+
|
|
546
|
+
except Exception:
|
|
547
|
+
pass
|
|
548
|
+
|
|
549
|
+
# Если задана конфигурация requests.
|
|
550
|
+
if type(self.__Config) == RequestsConfig:
|
|
551
|
+
# Закрытие сессии.
|
|
552
|
+
self.__Session.close()
|
|
553
|
+
# Обнуление сессии.
|
|
554
|
+
self.__Session = None
|
|
555
|
+
|
|
556
|
+
# Если задана конфигурация httpx.
|
|
557
|
+
if type(self.__Config) == HttpxConfig:
|
|
558
|
+
# Закрытие клиента.
|
|
559
|
+
self.__Client.close()
|
|
560
|
+
# Обнуление клиента.
|
|
561
|
+
self.__Client = None
|
|
562
|
+
|
|
563
|
+
def addProxy(self, Protocol: Protocols, Host: str, Port: int | str, Login: str | None = None, Password: str | None = None):
|
|
564
|
+
"""
|
|
565
|
+
Добавляет прокси для использования в запросах. Не работает с Selenium.
|
|
566
|
+
Protocol – протокол прокси-соединения;
|
|
567
|
+
Host – IP или адрес хоста;
|
|
568
|
+
Port – порт сервера;
|
|
569
|
+
Login – логин для авторизации;
|
|
570
|
+
Password – пароль для авторизации.
|
|
571
|
+
"""
|
|
572
|
+
|
|
573
|
+
# Добавление прокси.
|
|
574
|
+
self.__Proxies.append({
|
|
575
|
+
"protocol": Protocol.value,
|
|
576
|
+
"host": Host,
|
|
577
|
+
"port": str(Port),
|
|
578
|
+
"login": Login,
|
|
579
|
+
"password": Password
|
|
580
|
+
})
|
|
581
|
+
|
|
582
|
+
def initialize(self, Config: HttpxConfig | RequestsConfig | SeleniumConfig = RequestsConfig()):
|
|
583
|
+
"""
|
|
584
|
+
Задаёт конфигурацию и инициализирует модуль запросов. Вызывать после всех настроек.
|
|
585
|
+
Config – конфигурация.
|
|
586
|
+
"""
|
|
587
|
+
|
|
588
|
+
# Если задана конфигурация Selenium.
|
|
589
|
+
if type(Config) == SeleniumConfig:
|
|
590
|
+
# Сохранение конфигурации.
|
|
591
|
+
self.__Config = Config
|
|
592
|
+
|
|
593
|
+
try:
|
|
594
|
+
# Динамический импорт пакетов.
|
|
595
|
+
self.Options = importlib.import_module("selenium.webdriver.chrome.option")
|
|
596
|
+
self.Service = importlib.import_module("selenium.webdriver.chrome.service")
|
|
597
|
+
self.ChromeDriverManager = importlib.import_module("webdriver_manager.chrome")
|
|
598
|
+
self.TimeoutException = importlib.import_module("selenium.common.exceptions")
|
|
599
|
+
|
|
600
|
+
except:
|
|
601
|
+
raise SeleniumRequired()
|
|
602
|
+
|
|
603
|
+
# Инициализация выбранного браузера.
|
|
604
|
+
match Config.BrowserType:
|
|
605
|
+
|
|
606
|
+
case Browsers.Chrome: self.__InitializeChrome()
|
|
607
|
+
|
|
608
|
+
# Если задана конфигурация requests.
|
|
609
|
+
if type(Config) == RequestsConfig:
|
|
610
|
+
# Сохранение конфигурации.
|
|
611
|
+
self.__Config = Config
|
|
612
|
+
# Инициализация сессии.
|
|
613
|
+
self.__Session = requests.Session()
|
|
614
|
+
|
|
615
|
+
# Если задана конфигурация httpx.
|
|
616
|
+
if type(Config) == HttpxConfig:
|
|
617
|
+
# Сохранение конфигурации.
|
|
618
|
+
self.__Config = Config
|
|
619
|
+
# Инициализация клиента.
|
|
620
|
+
self.__Client = httpx.Client(http2 = Config.http2, proxies = self.__GetProxy())
|
|
621
|
+
|
|
622
|
+
#==========================================================================================#
|
|
623
|
+
# >>>>> SELENIUM <<<<< #
|
|
624
|
+
#==========================================================================================#
|
|
625
|
+
|
|
626
|
+
def executeJavaScript(self, Script: str, Async: bool = False, TriesCount: int = 3) -> WebResponse:
|
|
627
|
+
"""
|
|
628
|
+
Выполняет JavaScript на текущей странице браузера.
|
|
629
|
+
Script – исполняемый код;
|
|
630
|
+
Async – указывает, необходимо ли выполнить скрипт асинхронно;
|
|
631
|
+
TriesCount – количество попыток повтора при неудачном выполнении.
|
|
632
|
+
Требуется инициализация библиотеки Selenium!
|
|
633
|
+
"""
|
|
634
|
+
|
|
635
|
+
# Ответ.
|
|
636
|
+
Response = WebResponse()
|
|
637
|
+
|
|
638
|
+
# Если веб-драйвер инициализирован.
|
|
639
|
+
if self.__Browser != None:
|
|
640
|
+
# Результат выполнения скрипта.
|
|
641
|
+
Result = None
|
|
642
|
+
# Количество повторов.
|
|
643
|
+
CurrentTry = 0
|
|
644
|
+
# Состояние: вернул ли скрипт ответ.
|
|
645
|
+
IsLoaded = False
|
|
646
|
+
|
|
647
|
+
# Повторять, пока скрипт не вернёт ответ.
|
|
648
|
+
while IsLoaded == False:
|
|
649
|
+
|
|
650
|
+
try:
|
|
651
|
+
# Выполнение скрипта и запись результата.
|
|
652
|
+
Result = self.__Browser.execute_async_script(Script) if Async == True else self.__Browser.execute_script(Script)
|
|
653
|
+
|
|
654
|
+
except self.TimeoutException.TimeoutException:
|
|
655
|
+
# Установка свойств ответа.
|
|
656
|
+
Response.status_code = 408
|
|
657
|
+
|
|
658
|
+
except Exception:
|
|
659
|
+
# Инкремент количества повторов.
|
|
660
|
+
CurrentTry += 1
|
|
661
|
+
# Установка свойств ответа.
|
|
662
|
+
Response.status_code = 400
|
|
663
|
+
|
|
664
|
+
# Если достигнуто максимальное количество повторов, остановить повторные запросы.
|
|
665
|
+
if CurrentTry == TriesCount:
|
|
666
|
+
break
|
|
667
|
+
|
|
668
|
+
else:
|
|
669
|
+
# Переключение статуса выполнения скрипта.
|
|
670
|
+
IsLoaded = True
|
|
671
|
+
# Установка свойств ответа.
|
|
672
|
+
Response.status_code = 200
|
|
673
|
+
Response.text = Result
|
|
674
|
+
Response.content = bytes(Result)
|
|
675
|
+
|
|
676
|
+
else:
|
|
677
|
+
# Выброс исключения.
|
|
678
|
+
raise SeleniumRequired()
|
|
679
|
+
|
|
680
|
+
return Response
|
|
681
|
+
|
|
682
|
+
def getBrowserHandler(self) -> any:
|
|
683
|
+
"""
|
|
684
|
+
Возвращает дескриптор экземпляра браузера.
|
|
685
|
+
URL – адрес страницы;
|
|
686
|
+
TriesCount – количество попыток повтора при неудачном выполнении.
|
|
687
|
+
Требуется инициализация библиотеки Selenium!
|
|
688
|
+
"""
|
|
689
|
+
|
|
690
|
+
# Если веб-драйвер не инициализирован, выбросить исключение.
|
|
691
|
+
if self.__Browser == None: raise SeleniumRequired()
|
|
692
|
+
|
|
693
|
+
return self.__Browser
|
|
694
|
+
|
|
695
|
+
def load(self, URL: str, TriesCount: int = 3) -> WebResponse:
|
|
696
|
+
"""
|
|
697
|
+
Загружает HTML код страницы через Selenium.
|
|
698
|
+
URL – адрес запроса;
|
|
699
|
+
TriesCount – количество попыток повтора при неудачном выполнении.
|
|
700
|
+
"""
|
|
701
|
+
|
|
702
|
+
# Ответ.
|
|
703
|
+
Response = WebResponse()
|
|
704
|
+
# Индекс попытки.
|
|
705
|
+
Try = 0
|
|
706
|
+
# Проверка наличия конфигурации.
|
|
707
|
+
self.__CheckConfig()
|
|
708
|
+
|
|
709
|
+
# Пока не превышено количество попыток.
|
|
710
|
+
while Try < TriesCount and Response.status_code != 200:
|
|
711
|
+
# Инкремент повтора.
|
|
712
|
+
Try += 1
|
|
713
|
+
|
|
714
|
+
try:
|
|
715
|
+
# Выполнение запроса.
|
|
716
|
+
Response = self.__selenium_LOAD(URL)
|
|
717
|
+
|
|
718
|
+
except Exception as ExceptionData:
|
|
719
|
+
# Запись в лог ошибки: не удалось выполнить запрос.
|
|
720
|
+
if self.__Logging == True: logging.error("[SELENIUM-LOAD] Description: \"" + str(ExceptionData).split("\n")[0] + "\".")
|
|
721
|
+
|
|
722
|
+
return Response
|
|
723
|
+
|
|
724
|
+
#==========================================================================================#
|
|
725
|
+
# >>>>> ЗАПРОСЫ <<<<< #
|
|
726
|
+
#==========================================================================================#
|
|
727
|
+
|
|
728
|
+
def get(self, URL: str, Params: dict | None = None, Headers: dict | None = None, Cookies: dict | None = None, TriesCount: int = 3) -> requests.Response | httpx.Response:
|
|
729
|
+
"""
|
|
730
|
+
Отправляет GET запрос.
|
|
731
|
+
URL – адрес запроса;
|
|
732
|
+
Params – словарь параметров запроса;
|
|
733
|
+
Headers – словарь заголовков;
|
|
734
|
+
Cookies – словарь куков;
|
|
735
|
+
TriesCount – количество попыток повтора при неудачном выполнении.
|
|
736
|
+
"""
|
|
737
|
+
|
|
738
|
+
# Ответ.
|
|
739
|
+
Response = WebResponse()
|
|
740
|
+
# Индекс попытки.
|
|
741
|
+
Try = 0
|
|
742
|
+
# Проверка наличия конфигурации.
|
|
743
|
+
self.__CheckConfig()
|
|
744
|
+
|
|
745
|
+
# Название библиотеки.
|
|
746
|
+
LibName = None
|
|
747
|
+
|
|
748
|
+
# Пока не превышено количество попыток.
|
|
749
|
+
while Try < TriesCount and Response.status_code != 200:
|
|
750
|
+
# Инкремент повтора.
|
|
751
|
+
Try += 1
|
|
752
|
+
|
|
753
|
+
try:
|
|
754
|
+
|
|
755
|
+
# Если установлена конфигурация библиотеки requests.
|
|
756
|
+
if type(self.__Config) == RequestsConfig:
|
|
757
|
+
# Установка имени библиотеки.
|
|
758
|
+
LibName = "REQUESTS"
|
|
759
|
+
# Выполнение запроса.
|
|
760
|
+
Response = self.__requests_GET(URL, Params, Headers, Cookies)
|
|
761
|
+
|
|
762
|
+
# Если установлена конфигурация библиотеки httpx.
|
|
763
|
+
if type(self.__Config) == HttpxConfig:
|
|
764
|
+
# Установка имени библиотеки.
|
|
765
|
+
LibName = "HTTPX"
|
|
766
|
+
# Выполнение запроса.
|
|
767
|
+
Response = self.__httpx_GET(URL, Params, Headers, Cookies)
|
|
768
|
+
|
|
769
|
+
except Exception as ExceptionData:
|
|
770
|
+
# Запись в лог ошибки: не удалось выполнить запрос.
|
|
771
|
+
if self.__Logging == True: logging.error(f"[{LibName}-GET] Description: \"" + str(ExceptionData).split("\n")[0] + "\".")
|
|
772
|
+
|
|
773
|
+
return Response
|
|
774
|
+
|
|
775
|
+
def post(self, URL: str, Params: dict | None = None, Headers: dict | None = None, Cookies: dict | None = None, Data: any = None, JSON: dict | None = None, TriesCount: int = 3) -> requests.Response | httpx.Response:
|
|
776
|
+
"""
|
|
777
|
+
Отправляет POST запрос.
|
|
778
|
+
URL – адрес запроса;
|
|
779
|
+
Params – словарь параметров запроса;
|
|
780
|
+
Headers – словарь заголовков;
|
|
781
|
+
Cookies – словарь куков;
|
|
782
|
+
JSON – тело запроса;
|
|
783
|
+
TriesCount – количество попыток повтора при неудачном выполнении.
|
|
784
|
+
"""
|
|
785
|
+
|
|
786
|
+
# Ответ.
|
|
787
|
+
Response = WebResponse()
|
|
788
|
+
# Индекс попытки.
|
|
789
|
+
Try = 0
|
|
790
|
+
# Проверка наличия конфигурации.
|
|
791
|
+
self.__CheckConfig()
|
|
792
|
+
# Название библиотеки.
|
|
793
|
+
LibName = None
|
|
794
|
+
|
|
795
|
+
# Пока не превышено количество попыток.
|
|
796
|
+
while Try < TriesCount and Response.status_code != 200:
|
|
797
|
+
# Инкремент повтора.
|
|
798
|
+
Try += 1
|
|
799
|
+
|
|
800
|
+
try:
|
|
801
|
+
|
|
802
|
+
# Если установлена конфигурация библиотеки requests.
|
|
803
|
+
if type(self.__Config) == RequestsConfig:
|
|
804
|
+
# Установка имени библиотеки.
|
|
805
|
+
LibName = "REQUESTS"
|
|
806
|
+
# Выполнение запроса.
|
|
807
|
+
Response = self.__requests_POST(URL, Params, Headers, Cookies, Data, JSON)
|
|
808
|
+
|
|
809
|
+
# Если установлена конфигурация библиотеки httpx.
|
|
810
|
+
if type(self.__Config) == HttpxConfig:
|
|
811
|
+
# Установка имени библиотеки.
|
|
812
|
+
LibName = "HTTPX"
|
|
813
|
+
# Выполнение запроса.
|
|
814
|
+
Response = self.__httpx_POST(URL, Params, Headers, Cookies, Data, JSON)
|
|
815
|
+
|
|
816
|
+
except Exception as ExceptionData:
|
|
817
|
+
# Запись в лог ошибки: не удалось выполнить запрос.
|
|
818
|
+
if self.__Logging == True: logging.error(f"[{LibName}-POST] Description: \"" + str(ExceptionData).split("\n")[0] + "\".")
|
|
819
|
+
|
|
820
|
+
return Response
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: dublib
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: Коллекция модулей от DUB1401.
|
|
5
5
|
Author-email: DUB1401 <vlad.milosta@outlook.com>
|
|
6
6
|
License: This is free and unencumbered software released into the public domain.
|
|
@@ -44,6 +44,8 @@ Requires-Python: >=3.10
|
|
|
44
44
|
Description-Content-Type: text/markdown
|
|
45
45
|
License-File: LICENSE
|
|
46
46
|
Requires-Dist: fake_useragent
|
|
47
|
+
Requires-Dist: httpx
|
|
48
|
+
Requires-Dist: httpx[http2]
|
|
47
49
|
Requires-Dist: requests
|
|
48
50
|
|
|
49
51
|
# dublib
|
|
@@ -1,440 +0,0 @@
|
|
|
1
|
-
from fake_useragent import UserAgent as UserAgentGenerator
|
|
2
|
-
from dublib.Exceptions.WebRequestor import *
|
|
3
|
-
|
|
4
|
-
import importlib
|
|
5
|
-
import requests
|
|
6
|
-
import logging
|
|
7
|
-
import enum
|
|
8
|
-
|
|
9
|
-
#==========================================================================================#
|
|
10
|
-
# >>>>> ВСПОМОГАТЕЛЬНЫЕ ТИПЫ ДАННЫХ <<<<< #
|
|
11
|
-
#==========================================================================================#
|
|
12
|
-
|
|
13
|
-
class Browsers(enum.Enum):
|
|
14
|
-
"""
|
|
15
|
-
Перечисление типов поддерживаемых браузеров.
|
|
16
|
-
"""
|
|
17
|
-
|
|
18
|
-
Chrome = "Google Chrome"
|
|
19
|
-
#Firefox = "Mozilla Firefox"
|
|
20
|
-
#Edge = "Microsoft Edge"
|
|
21
|
-
|
|
22
|
-
class RequestsConfig:
|
|
23
|
-
"""
|
|
24
|
-
Конфигурация библиотеки requests.
|
|
25
|
-
"""
|
|
26
|
-
|
|
27
|
-
def __init__(self):
|
|
28
|
-
"""
|
|
29
|
-
Конфигурация библиотеки requests.
|
|
30
|
-
"""
|
|
31
|
-
|
|
32
|
-
#---> Генерация динамических свойств.
|
|
33
|
-
#==========================================================================================#
|
|
34
|
-
# Заголовки запросов.
|
|
35
|
-
self.Headers = {
|
|
36
|
-
"User-Agent": str(UserAgentGenerator.chrome)
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
def addHeader(self, Key: str, Value: int | str):
|
|
40
|
-
"""
|
|
41
|
-
Добавляет пользовательский заголовок запроса.
|
|
42
|
-
Key – ключ заголовка;
|
|
43
|
-
Value – значение заголовка.
|
|
44
|
-
"""
|
|
45
|
-
|
|
46
|
-
# Запись заголовка.
|
|
47
|
-
self.Headers[Key] = Value
|
|
48
|
-
|
|
49
|
-
def setReferer(self, Referer: str):
|
|
50
|
-
"""
|
|
51
|
-
Задаёт пользовательское значение заголовка Referer.
|
|
52
|
-
Referer – новое значение заголовка.
|
|
53
|
-
"""
|
|
54
|
-
|
|
55
|
-
self.Headers["Referer"] = Referer
|
|
56
|
-
|
|
57
|
-
def setUserAgent(self, UserAgent: str):
|
|
58
|
-
"""
|
|
59
|
-
Задаёт пользовательское значение заголовка User-Agent.
|
|
60
|
-
UserAgent – новое значение заголовка.
|
|
61
|
-
"""
|
|
62
|
-
|
|
63
|
-
self.Headers["User-Agent"] = UserAgent
|
|
64
|
-
|
|
65
|
-
class SeleniumConfig:
|
|
66
|
-
"""
|
|
67
|
-
Конфигурация библиотеки Selenium.
|
|
68
|
-
"""
|
|
69
|
-
|
|
70
|
-
def __init__(
|
|
71
|
-
self,
|
|
72
|
-
BrowserType: Browsers = Browsers.Chrome,
|
|
73
|
-
Headless: bool = False,
|
|
74
|
-
PageLoadTimeout: int = 75,
|
|
75
|
-
ScriptTimeout: int = 75,
|
|
76
|
-
WindowWidth: int = 1920,
|
|
77
|
-
WindowHeight: int = 1080
|
|
78
|
-
):
|
|
79
|
-
"""
|
|
80
|
-
Конфигурация библиотеки Selenium.
|
|
81
|
-
"""
|
|
82
|
-
|
|
83
|
-
#---> Генерация динамических свойств.
|
|
84
|
-
#==========================================================================================#
|
|
85
|
-
# Тип используемого браузера.
|
|
86
|
-
self.BrowserType = BrowserType
|
|
87
|
-
# Состояние: активен ли безрабочный режим.
|
|
88
|
-
self.Headless = Headless
|
|
89
|
-
# Тайм-аут загрузки страницы.
|
|
90
|
-
self.PageLoadTimeout = PageLoadTimeout
|
|
91
|
-
# Тайм-аут выполнения JavaScript.
|
|
92
|
-
self.ScriptTimeout = ScriptTimeout
|
|
93
|
-
# Ширина окна.
|
|
94
|
-
self.WindowWidth = WindowWidth
|
|
95
|
-
# Высота окна.
|
|
96
|
-
self.WindowHeight = WindowHeight
|
|
97
|
-
|
|
98
|
-
def setBrowserType(self, BrowserType: Browsers):
|
|
99
|
-
"""
|
|
100
|
-
Задаёт используемый браузер.
|
|
101
|
-
BrowserType – браузер.
|
|
102
|
-
"""
|
|
103
|
-
|
|
104
|
-
self.BrowserType = BrowserType
|
|
105
|
-
|
|
106
|
-
def setHeadless(self, Headless: bool):
|
|
107
|
-
"""
|
|
108
|
-
Переключает отображение окна браузера.
|
|
109
|
-
Headless – состояние отображение окна браузера.
|
|
110
|
-
"""
|
|
111
|
-
|
|
112
|
-
self.Headless = Headless
|
|
113
|
-
|
|
114
|
-
def setPageLoadTimeout(self, PageLoadTimeout: int):
|
|
115
|
-
"""
|
|
116
|
-
Задаёт тайм-аут загрузки страницы.
|
|
117
|
-
PageLoadTimeout – тайм-аут загрузки страницы в секундах.
|
|
118
|
-
"""
|
|
119
|
-
|
|
120
|
-
self.PageLoadTimeout = PageLoadTimeout
|
|
121
|
-
|
|
122
|
-
def setScriptTimeout(self, ScriptTimeout: int):
|
|
123
|
-
"""
|
|
124
|
-
Задаёт тайм-аут выполнения JavaScript.
|
|
125
|
-
PageLoadTimeout – тайм-аут выполнения JavaScript в секундах.
|
|
126
|
-
"""
|
|
127
|
-
|
|
128
|
-
self.ScriptTimeout = ScriptTimeout
|
|
129
|
-
|
|
130
|
-
def setWindowSize(self, Width: int, Height: int):
|
|
131
|
-
"""
|
|
132
|
-
Задаёт размер окна браузера.
|
|
133
|
-
Width – ширина окна в пикселях;
|
|
134
|
-
Height – высота окна в пикселях.
|
|
135
|
-
"""
|
|
136
|
-
|
|
137
|
-
self.WindowWidth = Width
|
|
138
|
-
self.WindowHeight = Height
|
|
139
|
-
|
|
140
|
-
class WebResponse:
|
|
141
|
-
"""
|
|
142
|
-
Эмуляция структуры ответа библиотеки requests.
|
|
143
|
-
"""
|
|
144
|
-
|
|
145
|
-
#==========================================================================================#
|
|
146
|
-
# >>>>> СТАТИЧЕСКИЕ СВОЙСТВА <<<<< #
|
|
147
|
-
#==========================================================================================#
|
|
148
|
-
|
|
149
|
-
# Статус ответа.
|
|
150
|
-
status_code = None
|
|
151
|
-
# Бинарное представление ответа.
|
|
152
|
-
content = None
|
|
153
|
-
# Текстовое представление ответа.
|
|
154
|
-
text = None
|
|
155
|
-
|
|
156
|
-
#==========================================================================================#
|
|
157
|
-
# >>>>> МЕТОДЫ <<<<< #
|
|
158
|
-
#==========================================================================================#
|
|
159
|
-
|
|
160
|
-
# Конструктор.
|
|
161
|
-
def __init__(self):
|
|
162
|
-
"""
|
|
163
|
-
Эмуляция структуры ответа библиотеки requests.
|
|
164
|
-
"""
|
|
165
|
-
|
|
166
|
-
#---> Генерация динамических свойств.
|
|
167
|
-
#==========================================================================================#
|
|
168
|
-
# Статус ответа.
|
|
169
|
-
status_code = None
|
|
170
|
-
# Бинарное представление ответа.
|
|
171
|
-
content = None
|
|
172
|
-
# Текстовое представление ответа.
|
|
173
|
-
text = None
|
|
174
|
-
|
|
175
|
-
#==========================================================================================#
|
|
176
|
-
# >>>>> ОСНОВНОЙ КЛАСС <<<<< #
|
|
177
|
-
#==========================================================================================#
|
|
178
|
-
|
|
179
|
-
class WebRequestor:
|
|
180
|
-
"""
|
|
181
|
-
Запросчик HTML кода веб-страниц.
|
|
182
|
-
"""
|
|
183
|
-
|
|
184
|
-
def __CheckConfigPresence(self) -> bool:
|
|
185
|
-
"""
|
|
186
|
-
Возвращает состояние: задана ли конфигурация.
|
|
187
|
-
"""
|
|
188
|
-
|
|
189
|
-
# Состояние: задана ли конфигурация.
|
|
190
|
-
IsConfigSet = False if self.__Session == None and self.__Browser == None else True
|
|
191
|
-
|
|
192
|
-
return IsConfigSet
|
|
193
|
-
|
|
194
|
-
def __InitializeChrome(self):
|
|
195
|
-
"""
|
|
196
|
-
Инициализирует браузер Google Chrome.
|
|
197
|
-
"""
|
|
198
|
-
|
|
199
|
-
# Закрытие браузера.
|
|
200
|
-
self.close()
|
|
201
|
-
# Опции веб-браузера.
|
|
202
|
-
ChromeOptions = self.Options.Options()
|
|
203
|
-
# Установка опций.
|
|
204
|
-
ChromeOptions.add_argument("--no-sandbox")
|
|
205
|
-
ChromeOptions.add_argument("--disable-dev-shm-usage")
|
|
206
|
-
ChromeOptions.add_argument("--disable-gpu")
|
|
207
|
-
ChromeOptions.add_experimental_option("excludeSwitches", ["enable-logging"])
|
|
208
|
-
# При отключённом режиме отладки скрыть окно браузера.
|
|
209
|
-
if self.__SeleniumConfig.Headless == True: ChromeOptions.add_argument("--headless=new")
|
|
210
|
-
# Инициализация браузера.
|
|
211
|
-
self.__Browser = self.selenium.webdriver.Chrome(service = self.Service.Service(self.ChromeDriverManager.ChromeDriverManager().install()), options = ChromeOptions)
|
|
212
|
-
# Установка размера окна браузера на FullHD для корректной работы сайтов.
|
|
213
|
-
self.__Browser.set_window_size(self.__SeleniumConfig.WindowWidth, self.__SeleniumConfig.WindowHeight)
|
|
214
|
-
# Установка максимального времени загрузки страницы и выполнения скрипта.
|
|
215
|
-
self.__Browser.set_page_load_timeout(self.__SeleniumConfig.PageLoadTimeout)
|
|
216
|
-
self.__Browser.set_script_timeout(self.__SeleniumConfig.ScriptTimeout)
|
|
217
|
-
|
|
218
|
-
def __GetByRequests(self, URL: str) -> WebResponse:
|
|
219
|
-
"""
|
|
220
|
-
Запрашивает страницу при помощи библиотеки requests.
|
|
221
|
-
"""
|
|
222
|
-
|
|
223
|
-
# Ответ.
|
|
224
|
-
Response = self.__Session.get(URL, headers = self.__RequestsConfig.Headers)
|
|
225
|
-
|
|
226
|
-
return Response
|
|
227
|
-
|
|
228
|
-
def __GetBySelenium(self, URL: str) -> WebResponse:
|
|
229
|
-
"""
|
|
230
|
-
Запрашивает страницу при помощи библиотеки Selenium.
|
|
231
|
-
"""
|
|
232
|
-
|
|
233
|
-
# Ответ.
|
|
234
|
-
Response = WebResponse()
|
|
235
|
-
|
|
236
|
-
try:
|
|
237
|
-
# Запрос страницы.
|
|
238
|
-
self.__Browser.get(URL)
|
|
239
|
-
|
|
240
|
-
except self.TimeoutException.TimeoutException:
|
|
241
|
-
# Установка свойств ответа.
|
|
242
|
-
Response.status_code = 408
|
|
243
|
-
|
|
244
|
-
except Exception:
|
|
245
|
-
# Установка свойств ответа.
|
|
246
|
-
Response.status_code = 499
|
|
247
|
-
|
|
248
|
-
else:
|
|
249
|
-
# Установка свойств ответа.
|
|
250
|
-
Response.status_code = 200
|
|
251
|
-
Response.text = self.__Browser.execute_script("return document.body.innerHTML;")
|
|
252
|
-
Response.content = bytes(Response.text)
|
|
253
|
-
|
|
254
|
-
return Response
|
|
255
|
-
|
|
256
|
-
def __init__(self, Logging: bool = False):
|
|
257
|
-
"""
|
|
258
|
-
Запросчик HTML кода веб-страниц.
|
|
259
|
-
Logging – переключает ведение логов при помощи стандартного модуля logging.
|
|
260
|
-
"""
|
|
261
|
-
|
|
262
|
-
#---> Генерация динамических свойств.
|
|
263
|
-
#==========================================================================================#
|
|
264
|
-
# Конфигурация requests.
|
|
265
|
-
self.__RequestsConfig = RequestsConfig()
|
|
266
|
-
# Конфигурация Selenium.
|
|
267
|
-
self.__SeleniumConfig = SeleniumConfig()
|
|
268
|
-
# Сессия запросов.
|
|
269
|
-
self.__Session = None
|
|
270
|
-
# Состояние: используется ли Selenium.
|
|
271
|
-
self.__IsSeleniumUsed = False
|
|
272
|
-
# Экземпляр веб-браузера.
|
|
273
|
-
self.__Browser = None
|
|
274
|
-
# Состояние: вести ли логи.
|
|
275
|
-
self.__Logging = Logging
|
|
276
|
-
|
|
277
|
-
def close(self):
|
|
278
|
-
"""
|
|
279
|
-
Закрывает запросчик.
|
|
280
|
-
"""
|
|
281
|
-
|
|
282
|
-
# Если для запросов используется Selenium.
|
|
283
|
-
if self.__IsSeleniumUsed == True:
|
|
284
|
-
|
|
285
|
-
try:
|
|
286
|
-
# Закрытие браузера.
|
|
287
|
-
self.__Browser.close()
|
|
288
|
-
self.__Browser.quit()
|
|
289
|
-
# Обнуление экземпляра.
|
|
290
|
-
self.__Browser = None
|
|
291
|
-
|
|
292
|
-
except Exception:
|
|
293
|
-
pass
|
|
294
|
-
|
|
295
|
-
else:
|
|
296
|
-
# Закрытие сессии.
|
|
297
|
-
self.__Session.close()
|
|
298
|
-
# Обнуление сессии.
|
|
299
|
-
self.__Session = None
|
|
300
|
-
|
|
301
|
-
def executeJavaScript(self, Script: str, Async: bool = False, TriesCount: int = 1) -> WebResponse:
|
|
302
|
-
"""
|
|
303
|
-
Выполняет JavaScript на текущей странице браузера.
|
|
304
|
-
Script – исполняемый код;
|
|
305
|
-
Async – указывает, необходимо ли выполнить скрипт асинхронно;
|
|
306
|
-
TriesCount – количество попыток повтора при неудачном выполнении.
|
|
307
|
-
Требуется инициализация библиотеки Selenium!
|
|
308
|
-
"""
|
|
309
|
-
|
|
310
|
-
# Ответ.
|
|
311
|
-
Response = WebResponse()
|
|
312
|
-
|
|
313
|
-
# Если веб-драйвер инициализирован.
|
|
314
|
-
if self.__Browser != None:
|
|
315
|
-
# Результат выполнения скрипта.
|
|
316
|
-
Result = None
|
|
317
|
-
# Количество повторов.
|
|
318
|
-
CurrentTry = 0
|
|
319
|
-
# Состояние: вернул ли скрипт ответ.
|
|
320
|
-
IsLoaded = False
|
|
321
|
-
|
|
322
|
-
# Повторять, пока скрипт не вернёт ответ.
|
|
323
|
-
while IsLoaded == False:
|
|
324
|
-
|
|
325
|
-
try:
|
|
326
|
-
# Выполнение скрипта и запись результата.
|
|
327
|
-
Result = self.__Browser.execute_async_script(Script) if Async == True else self.__Browser.execute_script(Script)
|
|
328
|
-
|
|
329
|
-
except self.TimeoutException.TimeoutException:
|
|
330
|
-
# Установка свойств ответа.
|
|
331
|
-
Response.status_code = 408
|
|
332
|
-
|
|
333
|
-
except Exception:
|
|
334
|
-
# Инкремент количества повторов.
|
|
335
|
-
CurrentTry += 1
|
|
336
|
-
# Установка свойств ответа.
|
|
337
|
-
Response.status_code = 400
|
|
338
|
-
|
|
339
|
-
# Если достигнуто максимальное количество повторов, остановить повторные запросы.
|
|
340
|
-
if CurrentTry == TriesCount:
|
|
341
|
-
break
|
|
342
|
-
|
|
343
|
-
else:
|
|
344
|
-
# Переключение статуса выполнения скрипта.
|
|
345
|
-
IsLoaded = True
|
|
346
|
-
# Установка свойств ответа.
|
|
347
|
-
Response.status_code = 200
|
|
348
|
-
Response.text = Result
|
|
349
|
-
Response.content = bytes(Result)
|
|
350
|
-
|
|
351
|
-
else:
|
|
352
|
-
# Выброс исключения.
|
|
353
|
-
raise SeleniumRequired()
|
|
354
|
-
|
|
355
|
-
return Response
|
|
356
|
-
|
|
357
|
-
def get(self, URL: str, TriesCount: int = 3) -> WebResponse:
|
|
358
|
-
"""
|
|
359
|
-
Получает HTML код страницы.
|
|
360
|
-
URL – адрес страницы;
|
|
361
|
-
TriesCount – количество попыток повтора при неудачном выполнении.
|
|
362
|
-
"""
|
|
363
|
-
|
|
364
|
-
# Ответ.
|
|
365
|
-
Response = WebResponse()
|
|
366
|
-
# Индекс попытки.
|
|
367
|
-
Try = 0
|
|
368
|
-
|
|
369
|
-
# Если задана конфигурация.
|
|
370
|
-
if self.__CheckConfigPresence() == True:
|
|
371
|
-
|
|
372
|
-
# Пока не превышено количество попыток.
|
|
373
|
-
while Try < TriesCount and Response.status_code != 200:
|
|
374
|
-
# Инкремент повтора.
|
|
375
|
-
Try += 1
|
|
376
|
-
|
|
377
|
-
try:
|
|
378
|
-
# Выполнение запроса.
|
|
379
|
-
Response = self.__GetBySelenium(URL) if self.__IsSeleniumUsed == True else self.__GetByRequests(URL)
|
|
380
|
-
|
|
381
|
-
except Exception as ExceptionData:
|
|
382
|
-
# Запись в лог ошибки: не удалось выполнить запрос.
|
|
383
|
-
if self.__Logging == True: logging.error("Some error occured during request: \"" + str(ExceptionData).split('\n')[0] + "\".")
|
|
384
|
-
|
|
385
|
-
else:
|
|
386
|
-
# Выброс исключения.
|
|
387
|
-
raise ConfigRequired()
|
|
388
|
-
|
|
389
|
-
return Response
|
|
390
|
-
|
|
391
|
-
def getBrowserHandler(self) -> any:
|
|
392
|
-
"""
|
|
393
|
-
Возвращает дескриптор экземпляра браузера.
|
|
394
|
-
URL – адрес страницы;
|
|
395
|
-
TriesCount – количество попыток повтора при неудачном выполнении.
|
|
396
|
-
Требуется инициализация библиотеки Selenium!
|
|
397
|
-
"""
|
|
398
|
-
|
|
399
|
-
# Если веб-драйвер не инициализирован, выбросить исключение.
|
|
400
|
-
if self.__Browser == None:
|
|
401
|
-
raise SeleniumRequired()
|
|
402
|
-
|
|
403
|
-
return self.__Browser
|
|
404
|
-
|
|
405
|
-
def initialize(self, Config: RequestsConfig | SeleniumConfig = RequestsConfig()):
|
|
406
|
-
"""
|
|
407
|
-
Задаёт конфигурацию и инициализирует модуль запросов.
|
|
408
|
-
Config – конфигурация.
|
|
409
|
-
"""
|
|
410
|
-
|
|
411
|
-
# Если задана конфигурация Selenium.
|
|
412
|
-
if type(Config) == SeleniumConfig:
|
|
413
|
-
# Переключение состояния Selenium.
|
|
414
|
-
self.__IsSeleniumUsed = True
|
|
415
|
-
# Сохранение конфигурации.
|
|
416
|
-
self.__SeleniumConfig = Config
|
|
417
|
-
|
|
418
|
-
try:
|
|
419
|
-
# Динамический импорт пакетов.
|
|
420
|
-
self.Options = importlib.import_module("selenium.webdriver.chrome.option")
|
|
421
|
-
self.Service = importlib.import_module("selenium.webdriver.chrome.service")
|
|
422
|
-
self.ChromeDriverManager = importlib.import_module("webdriver_manager.chrome")
|
|
423
|
-
self.TimeoutException = importlib.import_module("selenium.common.exceptions")
|
|
424
|
-
|
|
425
|
-
except:
|
|
426
|
-
raise SeleniumRequired()
|
|
427
|
-
|
|
428
|
-
# Инициализация выбранного браузера.
|
|
429
|
-
match Config.BrowserType:
|
|
430
|
-
|
|
431
|
-
case Browsers.Chrome: self.__InitializeChrome()
|
|
432
|
-
|
|
433
|
-
# Если задана конфигурация requests.
|
|
434
|
-
elif type(Config) == RequestsConfig:
|
|
435
|
-
# Переключение состояния Selenium.
|
|
436
|
-
self.__IsSeleniumUsed = False
|
|
437
|
-
# Сохранение конфигурации.
|
|
438
|
-
self.__RequestsConfig = Config
|
|
439
|
-
# Инициализация сессии.
|
|
440
|
-
self.__Session = requests.Session()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|