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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dublib
3
- Version: 0.1.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.1.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 = "Selenium or requests config required."
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.1.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,2 +1,4 @@
1
1
  fake_useragent
2
+ httpx
3
+ httpx[http2]
2
4
  requests
@@ -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