BeautifulSoup — парсинг HTML
BeautifulSoup (пакет beautifulsoup4, импорт from bs4 import BeautifulSoup) превращает HTML-страницу в дерево объектов, по которому удобно искать теги, классы и атрибуты. Это не загрузчик сайтов: сначала текст страницы получают через requests, httpx или файл на диске.
Практически это инструмент "достать нужные поля со страницы и привести их к структуре". Он особенно полезен, когда API нет, а данные публичны и доступны в HTML.
Путеводитель по инструментам: Инструменты и среды. Раздел про скрапинг в контексте файлов и сети: глава 31.
Установка
pip install beautifulsoup4 requests
# опционально — быстрый парсер —
pip install lxml
Команды ставят набор для HTML-парсинга:
beautifulsoup4даёт API для обхода DOM-дерева;requestsзагружает HTML по HTTP;lxmlподключает более быстрый движок разбора для крупных страниц.
| Пакет | Роль |
|---|---|
beautifulsoup4 | API для обхода DOM |
lxml | Парсер lxml (быстрее на больших страницах) |
html5lib | Толерантный разбор "грязного" HTML |
requests | HTTP GET/POST |
Минимальный пример
import requests
from bs4 import BeautifulSoup
url = "https://httpbin.org/html"
html = requests.get(url, timeout=10).text
soup = BeautifulSoup(html, "html.parser")
title = soup.find("h1")
print(title.get_text(strip=True) if title else "Заголовок не найден")
Это базовый поток "получить страницу и извлечь поле":
requests.get(...).textскачивает HTML как строку;BeautifulSoup(html, "html.parser")строит дерево элементов;find("h1")ищет первый заголовок уровняh1;get_text(strip=True)очищает пробелы и возвращает текст узла.
Цепочка: запрос → текст → soup → find → данные.
Выбор парсера
| Парсер | Плюсы | Минусы |
|---|---|---|
html.parser | Встроен в Python | Медленнее на огромных документах |
lxml | Скорость | Отдельная зависимость |
html5lib | Исправляет кривую вёрстку | Медленный |
soup = BeautifulSoup(html, "lxml")
Здесь меняется только парсер:
- BeautifulSoup API остаётся прежним;
"lxml"обычно даёт более высокую скорость обработки на больших документах.
Поиск элементов
# один элемент
first_link = soup.find("a", href=True)
# все совпадения
all_p = soup.find_all("p", class_="news-item")
# CSS-селекторы (удобно для сложной вёрстки)
items = soup.select("div.catalog > article h2 a")
Фрагмент показывает три способа поиска элементов:
find(...)возвращает одно первое совпадение;find_all(...)собирает список всех найденных узлов;select(...)применяет CSS-селектор, что удобно для сложной вложенности.
| Метод | Когда использовать |
|---|---|
find / find_all | Тег + class_, атрибуты |
select / select_one | CSS как в браузере |
.parent, .next_sibling | Обход дерева |
Извлечение текста и атрибутов:
text = element.get_text(strip=True, separator=" ")
href = element.get("href") # None, если атрибута нет
Этот код извлекает данные из уже найденного тега:
get_text(...)собирает текст дочерних узлов в одну строку;strip=Trueубирает лишние пробелы по краям;element.get("href")безопасно читает атрибут и возвращаетNone, если его нет.
Типовой сценарий — каталог
Код ITЗагрузка примера кода…
В примере собран полный мини-пайплайн скрапинга:
requests.get(...)получает HTML иraise_for_status()прерывает сценарий при HTTP-ошибке;BeautifulSoup(resp.text, "lxml")парсит страницу;- цикл по
soup.select(".product-card")извлекает карточки товаров; - проверки
if name and priceотбрасывают неполные записи; csv.DictWriterсохраняет результат в табличный файл для дальнейшей обработки.
Селекторы .product-card нужно подставить под реальную вёрстку (инструменты разработчика в браузере).
Ограничения и этика
- Уважайте robots.txt и условия сайта; учебные задания — на httpbin.org, своих страницах или API.
- Статический HTML не содержит контент, подгружаемый только JavaScript; тогда нужен браузерный движок (Playwright, Selenium) — см. главу 31.
- Частые запросы без паузы нагружают сервер — добавляйте
time.sleepи кэш.
Для больших краулеров смотрите Scrapy в экосистеме Python.
Частые ошибки новичков
- Нет
timeoutвrequests.get, и скрипт может зависнуть на неопределённое время. - Жёсткие CSS-селекторы без проверки
None, из-за чего парсер падает при изменении верстки. - Игнорирование кодировок и "грязного" текста (переносы, лишние пробелы, спецсимволы).
- Отсутствие пауз между запросами и адекватного
User-Agent.
Мини-шаблон безопасного извлечения:
node = soup.select_one(".title")
title = node.get_text(strip=True) if node else ""
Это шаблон безопасного чтения поля:
select_one(...)может вернутьNone, если элемент отсутствует;- тернарное выражение защищает от
AttributeErrorи даёт пустую строку как fallback; - подход полезен для "хрупкой" вёрстки, которая часто меняется.
Что делать после парсинга
Типичный следующий шаг — нормализация и сохранение в таблицу:
- собрать список словарей;
- загрузить в
pandas.DataFrame; - очистить дубликаты и пустые значения;
- сохранить в CSV/Parquet.
Для этого удобно перейти к Pandas — объединение таблиц, своды и временные ряды.
См. также
- Парсинг на Python — полный путеводитель по веб-парсингу
- HTTP и requests
- Работа с файлами, сетью и внешними API
- Инструменты и среды
Базовый разбор HTTP и HTTPS находится в отдельной статье — HTTP как основа веб-интеграций.