Инструменты Python для обработки HTML документов

Раздел: Обработка данных -> Парсинг и веб-скрапинг

Обзор библиотек для работы с HTML в Python

Как выполнять гибкий и удобный парсинг HTML с использованием BeautifulSoup и парсера lxml?

Основной и наиболее популярный подход - комбинация библиотеки BeautifulSoup с парсером lxml. BeautifulSoup предоставляет высокоуровневые методы для навигации, поиска и изменения HTML-дерева, а lxml обеспечивает высокую скорость парсинга и устойчивость к некорректной разметке.

from bs4 import BeautifulSoup

html_doc = '''
<html><body><h1>Заголовок</h1><p class="text">Пример текста</p></body></html>
'''
soup = BeautifulSoup(html_doc, 'lxml')
print(soup.h1.text)  # Заголовок
print(soup.find('p', class_='text').text)  # Пример текста

Python html библиотека (библиотеки python для работы с html (beautifulsoup, lxml и др.))

Выбор парсера lxml даёт преимущество в скорости и точности. Для установки необходим пакет lxml.

pip install lxml beautifulsoup4

Типичная ошибка: если lxml не установлен, BeautifulSoup автоматически переключится на встроенный парсер html.parser, что может привести к иной интерпретации сложных структур или к снижению производительности. Решение - всегда явно указывать парсер и убедиться, что он доступен.

Как использовать lxml напрямую без BeautifulSoup для парсинга HTML?

Библиотека lxml может работать самостоятельно через модуль lxml.html. Это даёт прямой доступ к XPath и CSS-селекторам, а также максимальную скорость.

from lxml import html

doc = html.fromstring('<div id="content">Текст</div>')
result = doc.xpath('//div[@id="content"]/text()')
print(result)  # ['Текст']

Цель: когда требуется минимальное количество промежуточных слоёв, например, при обработке больших объёмов данных.

Проблема: lxml не прощает невалидную разметку так же легко, как BeautifulSoup. Некоторые некорректные атрибуты могут вызвать ошибки парсинга. Решение - использовать parser = html.HTMLParser(remove_blank_text=True) для мягкой обработки.

Как выполнить парсинг HTML без установки дополнительных библиотек - с помощью встроенного парсера html.parser?

Модуль html.parser входит в стандартную библиотеку Python. Он прост, но не такой гибкий и быстрый как lxml или html5lib. Подходит для простых и небольших задач.

from html.parser import HTMLParser

class MyParser(HTMLParser):
    def handle_data(self, data):
        print('Найден текст:', data)

parser = MyParser()
parser.feed('<p>Простой текст</p>')

Случай использования: когда нельзя устанавливать сторонние пакеты (например, в ограниченной среде).

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

Как ускорить парсинг за счёт selectolax?

Библиотека selectolax (обёртка над Modest) обеспечивает очень высокую скорость работы с CSS-селекторами. Она не поддерживает XPath, но отлично справляется с задачей извлечения элементов по селекторам из больших HTML-файлов.

from selectolax.parser import HTMLParser

parser = HTMLParser('<div class="item">Значение</div>')
node = parser.css_first('.item')
print(node.text())  # Значение

Цель: получение максимальной производительности при пакетной обработке страниц.

Проблема: selectolax не поддерживает сложные CSS-селекторы (например, :has) и не умеет работать с некорректными атрибутами. Решение - предварительно очищать HTML или использовать другой парсер для сложных случаев.

Как получить более удобный API, похожий на jQuery, с помощью pyquery?

Библиотека pyquery позволяет использовать синтаксис jQuery для работы с HTML. Она основана на lxml, поэтому наследует его скорость.

from pyquery import PyQuery as pq

doc = pq('<ul><li class="item">Элемент</li></ul>')
print(doc('.item').text())  # Элемент

Случай использования: для разработчиков, привыкших к jQuery, и при необходимости цепочных вызовов.

Проблема: pyquery может быть избыточной для простых задач. При работе с некорректным HTML некоторые методы могут вести себя неожиданно.

Рассмотрим расширенные примеры, демонстрирующие решение типичных и неочевидных задач при парсинге HTML.

Пример
# Пример 1: Извлечение таблицы с объединёнными ячейками (rowspan/colspan) с помощью BeautifulSoup
from bs4 import BeautifulSoup

html = '''
<table>
  <tr><td rowspan="2">A</td><td>B</td></tr>
  <tr><td>C</td></tr>
</table>
'''
soup = BeautifulSoup(html, 'lxml')
rows = soup.find_all('tr')
for row in rows:
    cells = row.find_all('td')
    for cell in cells:
        print(cell.get('rowspan', '1'), cell.text)
# Результат: 2 A, 1 B, 1 C
2 A
1 B
1 C
Пример
# Пример 2: Использование XPath с lxml для выборки по тексту
from lxml import html

doc = html.fromstring('<div><p>Привет</p><p>Мир</p></div>')
result = doc.xpath('//p[contains(text(), "Мир")]/text()')
print(result)  # ['Мир']
['Мир']
Пример
# Пример 3: Обработка ошибок кодировки при загрузке страницы с requests и BeautifulSoup
import requests
from bs4 import BeautifulSoup

url = 'http://example.com'
try:
    resp = requests.get(url, timeout=5)
    resp.encoding = resp.apparent_encoding  # автоопределение кодировки
    soup = BeautifulSoup(resp.text, 'lxml')
    print(soup.title.text)
except requests.exceptions.RequestException as e:
    print('Ошибка сети:', e)
except Exception as e:
    print('Ошибка парсинга:', e)
Example Domain
Пример
# Пример 4: Парсинг HTML с использованием сессии и куки
import requests
from bs4 import BeautifulSoup

session = requests.Session()
session.get('http://example.com/login')
resp = session.get('http://example.com/dashboard')
soup = BeautifulSoup(resp.content, 'lxml')
username = soup.select_one('.user-name').text
print(f'Пользователь: {username}')
Пользователь: admin
Пример
# Пример 5: Обработка бесконечно вложенных списков с помощью рекурсии
from bs4 import BeautifulSoup

html = '<ul><li>1<ul><li>1.1</li></ul></li><li>2</li></ul>'
soup = BeautifulSoup(html, 'lxml')

def extract(ul):
    items = []
    for li in ul.find_all('li', recursive=False):
        text = li.contents[0].strip() if li.contents else ''
        sub = li.find('ul')
        items.append({'text': text, 'children': extract(sub) if sub else []})
    return items

result = extract(soup.ul)
print(result)
[{'text': '1', 'children': [{'text': '1.1', 'children': []}]}, {'text': '2', 'children': []}]
Пример
# Пример 6: Использование html5lib для максимально точного парсинга (соответствие стандарту WHATWG)
from bs4 import BeautifulSoup

# html5lib очень медленный, но точный
soup = BeautifulSoup('<p></p>', 'html5lib')
print(soup.p)  # закрывающий тег будет добавлен корректно
<p></p>

Библиотеки Python для работы с HTML (BeautifulSoup, lxml и др.) - comments

En
Python html библиотека (python)