Что такое парсинг и когда он законен

Парсинг — это автоматическое чтение и разбор HTML-страницы программой вместо человека, который открывает сайт в браузере. Технически ничего не мешает написать скрипт, который обходит сотни страниц за минуту, но у каждого сайта есть владелец, который вправе ограничить такой обход. Публично доступная страница не означает автоматического разрешения выкачивать с неё данные в промышленных масштабах — вопрос решает файл robots.txt и пользовательское соглашение конкретного сайта.

Проверка robots.txt перед началом работы

Файл robots.txt лежит в корне сайта по прямому адресу — например example.com/robots.txt — и описывает, каким роботам и какие разделы сайта разрешено или запрещено обходить. Строка Disallow с путём после неё запрещает автоматический обход этого раздела, а Crawl-delay задаёт минимальную паузу между запросами одного робота в секундах. Смотреть нужно на секцию с User-agent: *, применимую ко всем роботам без исключения, и на отдельную секцию с именем конкретного бота, если она есть — правила из именной секции имеют приоритет над общей.

Если Disallow закрывает раздел, где лежит нужная страница прогноза погоды, обходить это правило не стоит — формально запрет в robots.txt не защищён технически и его можно обойти программно, но это прямое нарушение воли владельца сайта. Разумная альтернатива — поискать официальный API того же сервиса погоды, у крупных метеосервисов он почти всегда есть и создан именно для автоматических запросов, в отличие от HTML-страницы для браузера.

Как получить HTML страницы с requests

Библиотека requests скачивает страницу одной строкой: requests.get с адресом страницы возвращает объект ответа, а его атрибут text содержит HTML целиком в виде строки. Обязательный параметр для реального использования — timeout, например timeout равный 10, который ограничивает время ожидания ответа сервера и не даёт скрипту зависнуть навсегда, если сайт не отвечает. Полезно также передать заголовок User-Agent, представляющий скрипт разумным образом, а не маскирующий его под чужой браузер, — прозрачность про то, что запрос идёт от программы, часть уважительного отношения к серверу.

Перед разбором стоит проверить код ответа через атрибут status_code: значение 200 означает успех, 404 — страница не найдена, а 429 обычно означает, что сервер посчитал частоту запросов слишком высокой и временно ограничил доступ. Метод raise_for_status у объекта ответа сам поднимет исключение при ошибочном коде, если его не хочется проверять вручную на каждой строке.

Как искать нужные данные через BeautifulSoup

Полученный текст HTML передают в конструктор BeautifulSoup вторым аргументом с указанием парсера, обычно html.parser — он входит в стандартную библиотеку и не требует установки дополнительных пакетов. Дальше по получившемуся объекту ищут нужные элементы методом find для первого совпадения или find_all для списка всех совпадений: например soup.find с тегом div и параметром class_ равным temperature найдёт первый блок с температурой, если разметка страницы использует именно такой класс.

У найденного элемента текст читается через атрибут text или метод get_text, который заодно убирает вложенные теги и оставляет только видимый текст. Для более точного поиска BeautifulSoup поддерживает CSS-селекторы через метод select — можно указать цепочку вида div.weather-card span.temp и получить строго вложенный элемент, а не первый попавшийся тег с похожим именем класса где-то на странице.

Хрупкость такого способа

Разметка сайта иногда меняется без предупреждения, и класс temperature однажды может превратиться в temp-value после редизайна — тогда скрипт молча начнёт возвращать пустые значения вместо ошибки. Полезная привычка — проверять результат поиска на None перед тем, как обращаться к его тексту, и явно логировать ситуацию, когда ожидаемый элемент не нашёлся.

Обработка ошибок сети

Сеть непредсказуема: сайт может быть временно недоступен, DNS может не ответить, соединение может оборваться на середине загрузки. Вызов requests.get стоит оборачивать в блок try с перехватом класса RequestException из requests.exceptions — этот класс объединяет большинство сетевых сбоев requests, включая таймаут и ошибку соединения, и перехват на этом уровне избавляет от необходимости ловить десяток разных исключений по отдельности.

Частота запросов и уважение к сайту

Даже при разрешённом robots.txt разделе не стоит слать запросы один за другим без паузы — десятки запросов в секунду с одного адреса выглядят для сервера как атака и создают реальную нагрузку на чужую инфраструктуру. Между запросами полезно ставить паузу функцией time.sleep хотя бы в одну-две секунды, а при указанном в robots.txt Crawl-delay — ориентироваться именно на это значение как на минимум.

Для регулярного сбора одних и тех же данных разумнее кешировать уже полученный результат локально и запрашивать сайт заново не чаще, чем данные реально обновляются — прогноз погоды меняется не каждую секунду, и опрашивать сайт раз в час обычно достаточно. Если у сервиса есть официальный API для того же прогноза, он почти всегда надёжнее самодельного парсера HTML: структура ответа остаётся стабильной при редизайне сайта, а лимиты запросов прописаны официально и не требуют угадывания разумной частоты.

  • проверить robots.txt сайта на предмет Disallow нужного раздела
  • изучить пользовательское соглашение на предмет прямого запрета автоматического сбора
  • ставить timeout на каждый запрос и обрабатывать RequestException
  • выдерживать паузу между запросами и не превышать разумную частоту обращений
  • предпочесть официальный API вместо парсинга HTML, если он существует

Собираем прогноз погоды по шагам

Предположим, что сайт погоды разрешает обход в robots.txt и на нужной странице внутри тега div с классом weather-card лежат вложенные элементы: span с классом city для названия города, span с классом temp для температуры и span с классом description для текстового описания вроде «облачно». После успешного requests.get и разбора через BeautifulSoup достаточно найти div.weather-card один раз методом find, а затем внутри него найти каждый из трёх span по его классу и прочитать text — три коротких вызова find дадут все три значения, которые можно собрать в единый читаемый вывод вроде Москва, плюс пять градусов, облачно.

Частые вопросы

Нужен ли аккаунт или API-ключ для requests и BeautifulSoup

Нет, обе библиотеки работают с обычными публичными страницами без регистрации — ключ понадобится только при переходе на официальный API конкретного сервиса, если он вообще есть.

Что делать, если сайт защищён от парсинга технически

Если владелец явно закрыл автоматический доступ через robots.txt, условия использования или техническую защиту, правильный путь — воспользоваться официальным API или другим источником данных, а не обходить защиту.

Почему find иногда возвращает None вместо элемента

Чаще всего это означает, что искомого класса или тега на странице больше нет — разметка изменилась после редизайна, страница отдала заглушку с ошибкой вместо нормального контента или элемент подгружается через JavaScript уже в браузере, после отправки исходного HTML.

Подходит ли requests для страниц с JavaScript-рендерингом

Нет, requests получает только исходный HTML без выполнения скриптов — если нужные данные подставляются в страницу уже в браузере через JavaScript, requests их просто не увидит, и для таких сайтов нужен другой инструмент.