## Как работает loader Loader находится в `modules/loader.py`. Его задача одна: скачать HTML-страницу и вернуть ее как строку. Есть загрузка через `curl`, загрузка через `urllib` и общая функция `download_html()`, которая выбирает порядок попыток. ## Заголовки запроса В начале файла задан словарь: ```python HEADERS ``` Он содержит HTTP-заголовки: ```text User-Agent Accept Accept-Language ``` Они нужны, чтобы сайт отдавал обычную HTML-страницу, как браузеру. ## Загрузка через curl Функция: ```python download_with_curl(url, timeout) ``` запускает системную команду `curl` через `subprocess.run`. Используются параметры: ```text -L переходить по редиректам --compressed принимать сжатый ответ --silent не печатать лишний прогресс --show-error показать ошибку, если она есть --max-time ограничить время загрузки -A передать User-Agent ``` Если `curl` что-то скачал в `stdout`, функция декодирует байты как UTF-8 и возвращает HTML-строку. Для ConsultantPlus этот способ оказался надежнее, чем чистый `urllib`, потому что сайт иногда нестабильно отдает большие страницы. ## Загрузка через urllib Функция: ```python download_with_urllib(url, timeout) ``` использует стандартную библиотеку Python: ```python urllib.request ``` Алгоритм: 1. Создается SSL-контекст. 2. Создается `Request` с заголовками `HEADERS`. 3. Вызывается `urlopen`. 4. Ответ читается и декодируется как UTF-8. SSL-проверка отключена: ```python context.check_hostname = False context.verify_mode = ssl.CERT_NONE ``` Это сделано для учебной устойчивости загрузки, чтобы сертификаты сайта не мешали выполнению задания. ## Главная функция Основная функция модуля: ```python download_html(url, retries=3, timeout=30.0) ``` Она возвращает HTML-код страницы. Логика выбора загрузчика: - если домен заканчивается на `consultant.ru`, сначала пробуется `curl`, затем `urllib`; - для остальных сайтов сначала пробуется `urllib`, затем `curl`. Это задается строкой: ```python is_consultant = urlparse(url).netloc.endswith("consultant.ru") ``` ## Повторные попытки В `download_html()` есть цикл: ```python for _ in range(retries): ``` На каждой попытке функция пробует все доступные загрузчики. Если оба способа не сработали, программа ждет `0.5` секунды и пробует еще раз. Если после всех попыток страница не загрузилась, выбрасывается ошибка: ```python RuntimeError ``` Эту ошибку затем обрабатывает crawler. ## Где используется loader Crawler вызывает loader через функцию: ```python download_html(url, retries=1, timeout=timeout) ``` То есть loader ничего не знает про УК РФ, статьи или обработку текста. Он только скачивает HTML, а вся логика обхода находится в `modules/crawler.py`.