Перейти к основному содержимому

BeautifulSoup — парсинг HTML

Разработчику

BeautifulSoup (пакет beautifulsoup4, импорт from bs4 import BeautifulSoup) превращает HTML-страницу в дерево объектов, по которому удобно искать теги, классы и атрибуты. Это не загрузчик сайтов: сначала текст страницы получают через requests, httpx или файл на диске.

Путеводитель по инструментам: Инструменты и среды. Раздел про скрапинг в контексте файлов и сети: глава 31.


Установка

pip install beautifulsoup4 requests
# опционально — быстрый парсер —
pip install lxml
ПакетРоль
beautifulsoup4API для обхода DOM
lxmlПарсер lxml (быстрее на больших страницах)
html5libТолерантный разбор «грязного» HTML
requestsHTTP 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 "Заголовок не найден")

Цепочка: запрос → текст → soup → find → данные.


Выбор парсера

ПарсерПлюсыМинусы
html.parserВстроен в PythonМедленнее на огромных документах
lxmlСкоростьОтдельная зависимость
html5libИсправляет кривую вёрсткуМедленный
soup = BeautifulSoup(html, "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Тег + class_, атрибуты
select / select_oneCSS как в браузере
.parent, .next_siblingОбход дерева

Извлечение текста и атрибутов:

text = element.get_text(strip=True, separator=" ")
href = element.get("href") # None, если атрибута нет

Типовой сценарий — каталог

import csv
import requests
from bs4 import BeautifulSoup

def scrape_products(url: str) -> list[dict]:
resp = requests.get(url, headers={"User-Agent": "StudyBot/1.0"}, timeout=15)
resp.raise_for_status()
soup = BeautifulSoup(resp.text, "lxml")
rows = []
for card in soup.select(".product-card"):
name = card.select_one(".title")
price = card.select_one(".price")
if name and price:
rows.append({
"name": name.get_text(strip=True),
"price": price.get_text(strip=True),
})
return rows

if __name__ == "__main__":
data = scrape_products("https://example.com/shop")
with open("prices.csv", "w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=["name", "price"])
writer.writeheader()
writer.writerows(data)

Селекторы .product-card нужно подставить под реальную вёрстку (инструменты разработчика в браузере).


Ограничения и этика

  • Уважайте robots.txt и условия сайта; учебные задания — на httpbin.org, своих страницах или API.
  • Статический HTML не содержит контент, подгружаемый только JavaScript; тогда нужен браузерный движок (Playwright, Selenium) — см. главу 31.
  • Частые запросы без паузы нагружают сервер — добавляйте time.sleep и кэш.

Для больших краулеров смотрите Scrapy в экосистеме Python.


См. также


См. также

Другие статьи этого же раздела в боковом меню (как на странице «О разделе»).