BeautifulSoup: парсинг HTML по-человечески
BeautifulSoup превращает строку HTML в удобное дерево, по которому легко искать.
BeautifulSoup (bs4) — библиотека для парсинга HTML и XML. Она строит дерево из тегов и даёт простые методы поиска:find,find_all, поиск по тегу, классу и атрибутам.
Разбирать HTML стандартным html.parser можно, но утомительно. BeautifulSoup делает то же самое в разы удобнее: ты говоришь «найди все div с классом product» — и получаешь список объектов, у каждого из которых легко взять текст и атрибуты. Это самый популярный инструмент для статического HTML.
Важно: bs4 — внешняя библиотека, в браузерном раннере её нет. Код ниже запускается на твоём компьютере. Установка:
pip install beautifulsoup4 lxmllxml — быстрый движок-парсер, который BeautifulSoup использует под капотом. Базовый разбор:
from bs4 import BeautifulSoup
html = '''
<div class="product">
<h2 class="title">Ноутбук Pro</h2>
<span class="price">79990</span>
</div>
'''
soup = BeautifulSoup(html, 'lxml')
print(soup.find('h2').text) # Ноутбук Pro
print(soup.find('span', class_='price').text) # 79990find и find_all
Два главных метода: find возвращает первый подходящий элемент, find_all — список всех. Искать можно по тегу, классу, id и любым атрибутам.
# первый элемент
title = soup.find('h2', class_='title')
# все элементы
products = soup.find_all('div', class_='product')
# по атрибуту
link = soup.find('a', attrs={'data-id': '123'})
# по нескольким тегам
headers = soup.find_all(['h1', 'h2', 'h3'])Как работает под капотом
BeautifulSoup принимает строку HTML и движок-парсер (lxml, html.parser или html5lib) и строит дерево объектов Tag и NavigableString. У каждого тега есть .text (весь вложенный текст), .attrs (словарь атрибутов) и навигация: .parent, .children, .find_next_sibling(). Поиск find_all обходит дерево и собирает совпадения. Главная ценность — устойчивость: даже «грязный» HTML с незакрытыми тегами bs4 разберёт без падения.
Объекты дерева: Tag и NavigableString
BeautifulSoup представляет документ двумя главными типами объектов. Tag — это элемент с именем, атрибутами и содержимым; у него есть .name, .attrs, .text и методы поиска. NavigableString — это текстовый фрагмент внутри тега. Понимание различия избавляет от типичной путаницы: tag.text склеивает весь вложенный текст рекурсивно, тогда как tag.string вернёт значение только если внутри ровно один текстовый узел, иначе None.
Извлекать атрибуты надёжнее через tag.get('href'), а не tag['href']: первый вернёт None при отсутствии атрибута, второй бросит KeyError. У ссылок и картинок это особенно важно, потому что разметка бывает неполной. Ещё одна частая операция — получить «чистый» текст без вложенных тегов через get_text(strip=True), который заодно убирает крайние пробелы. Эти мелочи отличают код, который стабильно работает на реальных «грязных» страницах, от кода, который красиво выглядит только на учебном примере.
Частые ошибки
- Писать
classвместоclass_.class— зарезервированное слово Python, поэтому параметр называетсяclass_. - Брать
.textуNone. Еслиfindничего не нашёл, он вернётNone— и.textупадёт. Проверяй результат. - Не указывать парсер. Лучше явно задавать
'lxml', иначе поведение зависит от окружения.
Best practices
- Всегда проверяй, что
findвернул элемент, прежде чем брать.text. - Используй
lxmlдля скорости и устойчивости. - Извлекай атрибуты через
tag.get('href')— он вернётNone, а не кинет ошибку при отсутствии.
Стоит знать про выбор парсера-движка. BeautifulSoup сам ничего не парсит — он надстройка над движком: быстрым lxml, встроенным html.parser (без зависимостей, но помедленнее) или максимально терпимым к битой разметке html5lib. Для большинства задач выбирают lxml как баланс скорости и устойчивости. Явное указание движка делает поведение кода одинаковым на любой машине — иначе BeautifulSoup возьмёт что найдёт, и результат может незаметно отличаться между окружениями.
Когда нужно не просто прочитать, а немного изменить разметку перед сохранением, BeautifulSoup умеет и это: удалять лишние теги (tag.decompose()), извлекать только текст (get_text()) или разворачивать обёртки (unwrap()). Для скрейпинга это пригождается при очистке: например, вырезать из описания товара рекламные вставки или скрипты, оставив чистый текст. Гибкость дерева делает bs4 не только инструментом поиска, но и удобным средством предобработки HTML перед тем, как сохранить результат в датасет.
Итог: BeautifulSoup — главный инструмент для статического HTML. Запомни связку BeautifulSoup(html, 'lxml') → find/find_all → .text/.get().