Взаимодействие с сетью

Работа с зеркалами

Для начала стоит упомянуть что сайт rezka.ag имеет множество постоянно меняющихся зеркал, с которыми библиотека так же умеет работать:

from HDrezka import HDrezka


# Установив зеркало, все запросы будут направляться через него
main_page = HDrezka(mirror="https://hdrezka8benxe.org").get()
print(main_page.url)
# >>> https://hdrezka8benxe.org/


# Однако любые запросы сделанные напрямую с использованием url не будут использовать зеркало
main_page = HDrezka().get(url="https://rezka.ag/")
print(main_page.url)
# >>> https://rezka.ag/

Примечание

После установки зеркала, все запросы отправленные с помощью библиотеки будут отправляться на данное зеркало до тех пор, пока программа не прекратит свою работу или зеркало не будет изменено повторно.

Connector и работа с ним

Механизм который позволяет работать с зеркалами(и не только) называется коннектором. Connector - это фундаментальный объект для работы с сетью в данной библиотеке. Именно через него будут проходить все ваши интернет запросы, а понимание принципов его работы позволит вам работать с библиотекой более гибко. Библиотека предоставляет собственный RequestConnector, что установлен по умолчанию:

from HDrezka.connector import RequestConnector

my_connector = RequestConnector()
print(my_connector.user_agent)  # Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:120.0) Gecko/20100101 Firefox/119.0
response = my_connector.get(url="https://httpstat.us/200")
print(response.status_code)
# >>> 200
print(response.text)
# >>> 200 OK

Но сам по себе коннектор не особо полезен, ведь по большей части он реализует те же возможности что доступны напрямую из requests. Однако, если передать коннектор в NetworkClient, в качестве аргумента, тогда все запросы из библиотеки будут проходить через данный коннектор. Это происходит за счёт того что класс NetworkClient является одиночкой и любые изменения в любом из его экземпляров затронут и все остальные.

from HDrezka import HDrezka
from HDrezka.connector import RequestConnector, NetworkClient

client = NetworkClient(connector=RequestConnector)

# Обратите внимание на то что NetworkClient позволяет напрямую обращаться к RequestConnector
client.domain = "hdrezka8benxe.org"  # устанавливаем домен зеркала

main_page = HDrezka().get()
print(main_page.url)
# >>> https://hdrezka8benxe.org/

# Всё ещё любые запросы сделанные напрямую с использованием url не будут использовать зеркало
main_page = HDrezka().get(url="https://rezka.ag/")
print(main_page.url)
# >>> https://rezka.ag/

Создание собственных коннекторов

Базовый RequestConnector хоть и позволяет работать с сетью на базовом уровне, но всё же имеет довольно примитивную реализацию. Поэтому вполне возможно что вам однажды станет его недостаточно, на этот случай предусмотрено создание собственных коннекторов. Как и RequestConnector который является наследником базового абстрактного класса Connector любой ваш собственный коннектор должен быть его потомком, а так же согласно базовой структуре должен иметь методы get и post. В качестве примера давайте создадим коннектор с возможностью логирования всех проходящих через него запросов:

import logging
import sys
from typing import Union, Dict, Any

import requests

from HDrezka import HDrezka
from HDrezka.connector import NetworkClient, Connector

logging.basicConfig(level=logging.INFO, stream=sys.stdout, format="%(asctime)s | %(levelname)-8s | %(message)s")


class MyConnector(Connector):
    def get(self, url: Union[str, bytes], **kwargs: Dict[str, Any]):
        logging.info("GET request to url = %s with kwargs = %s", url, kwargs)
        return requests.get(url, headers=self.get_headers(url), proxies=self.proxies, **kwargs, timeout=15)

    def post(self, url: Union[str, bytes], **kwargs: Dict[str, Any]):
        logging.info("POST request to url = %s with kwargs = %s", url, kwargs)
        return requests.post(url, headers=self.get_headers(url), proxies=self.proxies, **kwargs, timeout=15)


NetworkClient(connector=MyConnector)

hdrezka = HDrezka()
collections = hdrezka.collections().get()
list_posters = collections[0].get()
print(list_posters)

# >>> 2024-04-01 18:21:55,46 | INFO     | GET request to url = https://rezka.ag/collections/ with kwargs = {}
# >>> 2024-04-01 18:21:55,97 | INFO     | GET request to url = https://rezka.ag/collections/3482-serialy-okko/ wit...
# >>> [Poster("Михаил Горшенёв. Легенда о Короле и Шуте"), Poster("Ласт квест"), Poster("Волшебный участок"), Poste...

Как видим, теперь все запросы, создаваемые библиотекой, проходят через наш коннектор и логируются. Использование данного коннектора ограничивается исключительно вашими потребностями. В качестве дополнительной идеи можно добавить кэширование запросов в базу данных (БД) и при повторении запросов извлекать их оттуда, вместо создания нового запроса к серверу.