Обзор библиотеки BeautifulSoup: парсинг веб-страниц на Python
Основы работы с BeautifulSoup
Как получить и разобрать HTML-страницу с помощью BeautifulSoup?
Библиотека BeautifulSoup (bs4) используется для извлечения данных из HTML и XML документов. Основной способ применения — совместно с библиотекой requests для загрузки страницы и последующего парсинга.
import requests
from bs4 import BeautifulSoup
url = 'https://example.com'
response = requests.get(url)
response.encoding = 'utf-8' # чтобы избежать проблем с кодировкой
soup = BeautifulSoup(response.text, 'html.parser')
библиотека beautifulsoup python (библиотека beautifulsoup в python)
Далее объект soup позволяет искать элементы с помощью методов find() и find_all().
Типичная ошибка: если страница возвращает статус 4xx или 5xx, код упадёт с исключением. Рекомендуется проверять response.raise_for_status() или использовать try/except.
Как выбрать элементы по CSS классу или ID?
Вместо поиска с find/find_all можно использовать метод select(), принимающий CSS-селектор. Это удобно для сложных запросов.
soup.select('div.content p')
soup.select('#main-header')
soup.select('a.external-link')
Python requests beautifulsoup (веб-скрапинг с requests и beautifulsoup)
Ошибка: неверный синтаксис селектора (например, пропущена точка перед классом). Проверьте селектор в консоли браузера.
Как найти элементы по текстовому содержимому с помощью регулярных выражений?
Метод find_all() поддерживает фильтр с помощью регулярного выражения из модуля re.
import re
soup.find_all('p', text=re.compile(r'\bPython\b'))
Html в файлах python (обработка html файлов в python)
Этот код вернёт все абзацы, содержащие слово Python как целое слово.
Проблема: если текст разбит на несколько дочерних узлов, регулярка может не сработать. Используйте .string или объединяйте текст через get_text().
Как парсить страницы, загружаемые через JavaScript?
BeautifulSoup не умеет выполнять JavaScript. Для динамических страниц нужен Selenium, который эмулирует браузер, а затем передаёт полученный HTML в BeautifulSoup.
from selenium import webdriver
from bs4 import BeautifulSoup
driver = webdriver.Chrome()
driver.get('https://example.com/dynamic')
html = driver.page_source
driver.quit()
soup = BeautifulSoup(html, 'html.parser')
Трудности: высокая нагрузка, необходимость установки драйвера и синхронизации ожидания загрузки контента (WebDriverWait).
Как использовать BeautifulSoup для парсинга XML?
BeautifulSoup поддерживает XML через парсер lxml-xml или встроенный xml.
soup = BeautifulSoup(xml_data, 'xml') # требуется lxml
# или
soup = BeautifulSoup(xml_data, 'lxml-xml')
После этого все методы работают аналогично HTML, только учитывается структура XML-документа.
Ошибка: если не установлен lxml, используется стандартный парсер, который может неправильно обработать XML-сущности. Установите pip install lxml.
Цели и случаи использования каждого варианта
Основной подход с requests и find() подходит для простых статичных страниц. CSS-селекторы удобны при работе с известным шаблоном документа. Регулярные выражения применяются, когда нужно найти элементы по тексту с точным или шаблонным совпадением. Selenium необходим для сайтов, где контент подгружается динамически. XML-парсер используется при разборе фидов, конфигураций или API-ответов в формате XML.
Расширенные примеры работы с BeautifulSoup
Ниже приведены подробные примеры с кодом и ожидаемым результатом.
Пример 1: Парсинг таблицы и извлечение данных
html = '''
Имя Возраст
Анна 25
Иван 30
'''
soup = BeautifulSoup(html, 'html.parser')
rows = soup.find_all('tr')
data = []
for row in rows:
cols = row.find_all(['th', 'td'])
data.append([col.get_text(strip=True) for col in cols])
print(data)
[['Имя', 'Возраст'], ['Анна', '25'], ['Иван', '30']]
Объяснение: перебираем строки, собираем заголовки и ячейки. Метод get_text(strip=True) удаляет лишние пробелы.
Пример 2: Извлечение всех ссылок с атрибутами
html = 'Ссылка 1 Ссылка 2'
soup = BeautifulSoup(html, 'html.parser')
for a in soup.find_all('a'):
print(a.get('href'), a.get('class'), a.text)
/page1 ['link'] Ссылка 1 /page2 None Ссылка 2
Метод get() возвращает значение атрибута или None, если атрибут отсутствует.
Пример 3: Работа с вложенными тегами и навигация по дереву
html = 'Текст жирный и курсив
'
soup = BeautifulSoup(html, 'html.parser')
p = soup.p
print(p.contents) # список потомков
print(p.b.string) # текст внутри
['Текст ', жирный, ' и ', курсив] жирный
Атрибут .contents даёт все дочерние элементы, включая текст. .string возвращает текст, только если у тега один потомок-строка.
Пример 4: Использование find_all с несколькими классами и ограничением количества
html = 'ПервыйВторой'
soup = BeautifulSoup(html, 'html.parser')
soup.find_all('div', class_='a b') # точное совпадение списка классов
soup.find_all('div', class_=re.compile(r'\ba\b')) # любой div с классом 'a'
[Первый] [Первый,Второй]
Если классы перечислены через запятую в class_, BeautifulSoup ищет элемент, у которого классы совпадают полностью (порядок не важен). Для частичного поиска используйте регулярное выражение или CSS-селектор.
Пример 5: Модификация документа и вывод изменённого HTML
soup = BeautifulSoup('Старый текст
', 'html.parser')
soup.p.string = 'Новый текст'
soup.b = 'добавлен' # это не сработает, нужно использовать append или new_tag
# Правильный способ:
tag = soup.new_tag('b')
tag.string = 'добавлен'
soup.p.append(tag)
print(soup.prettify())
Новый текст добавлен
new_tag создаёт новый элемент, затем его можно вставлять в дерево через append, insert или replace_with.
Пример 6: Обработка динамических страниц (Selenium + BeautifulSoup с ожиданием)
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from bs4 import BeautifulSoup
driver = webdriver.Chrome()
driver.get('https://example.com/dynamic')
# ждём появления элемента с определённым селектором
wait = WebDriverWait(driver, 10)
wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, 'div.result')))
html = driver.page_source
driver.quit()
soup = BeautifulSoup(html, 'html.parser')
results = soup.select('div.result')
for r in results:
print(r.get_text(strip=True))
Этот пример демонстрирует безопасное получение динамически загруженного контента.