все статьи
12 октября 2026 г.·8 мин

Как написать парсер на Python: пример Beautiful Soup

Практика Beautiful Soup на тестовой HTML-разметке: извлечение полей, проверка значений, дубли и безопасная работа с источником.

PythonПарсерScrapyАвтоматизацияДанные

Автор: Shcoder, независимый разработчик

Парсер сайта на Python автоматически получает разрешённые данные из веб-страниц, приводит их к согласованному формату и передаёт в таблицу, API или отчёт. Это полезно для регулярного мониторинга цен и объявлений, но надёжный парсер — не просто скрипт, который однажды нашёл текст: он также проверяет результат и сообщает, когда источник изменился.

Если источник предлагает подходящий API или выгрузку, обычно стоит начать с них. HTML-парсер выбирают, когда нужных данных иначе получить нельзя и правила источника это допускают. Примеры ниже показывают подход к качеству данных, а не готовый парсер конкретного сайта.

Что должен решить парсер

До выбора Python-библиотеки опишите задачу как поток данных:

  1. Источник: страницы, API или файлы, к которым есть разрешённый доступ.
  2. Поля: какие значения нужны, например название, цена, дата и ссылка на карточку.
  3. Правила: как нормализовать валюту, даты, пробелы и пропущенные значения.
  4. Обновление: как часто проверять источник с учётом его правил и допустимой нагрузки.
  5. Результат: CSV, Google Sheets, база данных, API или уведомление.
  6. Сбой: что сохранить в лог и кому сообщить, если данные временно недоступны.

Так становится понятно, нужен ли небольшой скрипт, планировщик задач или отдельный сервис с хранилищем и мониторингом.

Минимальное извлечение и проверка

Для статичной HTML-страницы часто достаточно BeautifulSoup. Ниже — самодостаточный пример на тестовой разметке: он извлекает записи, приводит цену к числу и пропускает карточки без обязательных полей.

Установите библиотеку:

python -m pip install beautifulsoup4
from decimal import Decimal, InvalidOperation
from urllib.parse import urljoin

from bs4 import BeautifulSoup

base_url = "https://example.test/"
html = """
<article class="listing">
  <a class="listing__link" href="/item/42">
    <h2 class="listing__title">Пример объявления</h2>
  </a>
  <span class="listing__price">1 250.50</span>
</article>
"""

soup = BeautifulSoup(html, "html.parser")
items = []

for card in soup.select("article.listing"):
    title = card.select_one(".listing__title")
    link = card.select_one("a.listing__link")
    price_node = card.select_one(".listing__price")

    href = link.get("href") if link else None
    if not title or not href or not price_node:
        continue

    raw_price = price_node.get_text(" ", strip=True).replace(" ", "")
    try:
        price = Decimal(raw_price)
    except InvalidOperation:
        continue

    items.append({
        "title": title.get_text(" ", strip=True),
        "url": urljoin(base_url, href),
        "price": price,
    })

print(items)

Сохраните код в parse_listing.py и запустите python parse_listing.py. Для приведённой тестовой карточки результат будет таким:

[{'title': 'Пример объявления', 'url': 'https://example.test/item/42', 'price': Decimal('1250.50')}]

Селекторы .listing, .listing__title и остальные здесь условные: для конкретного источника их подбирают по разрешённой HTML-разметке. example.test и разметка выше — локальная фикстура; скрипт не отправляет сетевых запросов. Если сервер отдаёт только пустую оболочку, а данные появляются в браузере после JavaScript, нужно проверить официальный API или выбрать инструмент с браузерным рендерингом. Не следует автоматически переходить к обходу ограничений.

Для сетевых запросов задают конечный таймаут, проверяют HTTP-статус и обрабатывают временные ошибки. См. документацию HTTPX по таймаутам и Scrapy по задержкам между запросами. Для HTML-разметки есть руководство Beautiful Soup. Частоту выбирают по правилам и поведению конкретного источника, а не по максимальной технической скорости.

Как сделать сбор устойчивым

Beautiful Soup или Scrapy

BeautifulSoup помогает разобрать уже полученный HTML и подходит для небольшого числа страниц, когда достаточно извлечь поля. Scrapy удобнее, когда нужно обходить много разрешённых страниц, управлять очередью запросов, обрабатывать результаты через pipeline и ограничивать частоту для домена. В документации Scrapy параметр DOWNLOAD_DELAY задаёт минимальную задержку между запросами к одному домену; конкретные значения всё равно сверяют с правилами источника.

Проверяйте поля до сохранения

Пустая цена или дата могут означать изменение HTML, а не отсутствие значения в объявлении. Задайте обязательные поля и диапазоны, посчитайте пропуски, проверяйте дату обновления и не записывайте некорректный результат как успешный импорт.

Убирайте дубли

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

Разделяйте сбор и уведомления

Сначала сохраните и проверьте данные, затем определите, что действительно изменилось, и только после этого отправляйте уведомление. Такой порядок не создаёт повторные сообщения после перезапуска задачи.

Записывайте полезные логи

Логируйте время запуска, число просмотренных страниц, число валидных записей и тип ошибки. Не записывайте в логи секреты, cookies или персональные данные, если они не нужны для задачи.

Планируйте сопровождение

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

Доступ и ограничения источника

Перед сбором проверьте условия использования и разрешённый способ доступа. Файл robots.txt описывает инструкции для автоматических клиентов, но сам по себе не является разрешением на использование данных. Не обходите вход в аккаунт, CAPTCHA, paywall, rate limits или другие технические меры; при сомнениях согласуйте доступ с владельцем источника. Стандарт Robots Exclusion Protocol отдельно описывает правила для автоматических клиентов.

Когда нужен не скрипт, а сервис

Одноразовую таблицу можно обработать локальным скриптом. Регулярный мониторинг с историей изменений, расписанием, несколькими источниками, уведомлениями и административным контролем уже требует эксплуатации: хранения, повторных попыток, логов и проверки качества.

В кейсе FlatRentBy регулярный сбор объявлений связан с фильтрами и Telegram-уведомлениями. Если нужно автоматизировать похожую задачу, сначала зафиксируем источник, поля и формат результата в кратком брифе на разработку парсера. Готовое ТЗ не обязательно.

Для самостоятельной практики можно пройти бесплатный курс Python для автоматизации: в нём сбор файлов и обработка данных доводятся до запускаемого проекта.

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

Можно ли собирать данные с любого сайта?

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

Чем парсер отличается от обычного скрипта?

Парсер извлекает поля из структурированного текста или разметки. Скрипт автоматизации может дополнительно объединять файлы, вызывать API, преобразовывать данные, формировать отчёты и отправлять уведомления.

Можно ли получать данные почти в реальном времени?

Это зависит от источника, его правил и нагрузки. Реалистичный интервал определяют после проверки доступа и объёма данных; обещать частоту заранее без этих сведений нельзя.

После получения данных часто нужно собрать несколько выгрузок и очистить повторы. Для этого есть отдельный пример, как объединить CSV-файлы на Python и проверить результат, и инструкция по регулярному запуску скрипта на Linux.

Хотите автоматизировать рутинные задачи?

Создаю парсеры, интеграции и скрипты, которые экономят время команды.