Извлечение данных стандартной библиотекой
Иногда нужные данные можно достать без тяжёлых библиотек — стандартными средствами Python.
Для простых задач — вытащить все ссылки, найти e-mail, очистить текст — хватает модулейreиhtml.parserиз стандартной библиотеки. Они работают где угодно, включая браузер.
Прежде чем тянуть BeautifulSoup, полезно понять, как извлекать данные «руками». Это и быстрее для мелких задач, и даёт интуицию о том, что библиотеки делают за тебя. Начнём с извлечения всех ссылок из HTML с помощью стандартного html.parser — этот код реально работает в нашем раннере.
Попробуй сам ▶
from html.parser import HTMLParser
page = '''
<ul>
<li><a href="/python">Python</a></li>
<li><a href="/sql" class="hot">SQL</a></li>
<li><a href="https://ext.example">Внешняя</a></li>
</ul>
'''
class LinkGrabber(HTMLParser):
def __init__(self):
super().__init__()
self.links = []
def handle_starttag(self, tag, attrs):
if tag == 'a':
href = dict(attrs).get('href')
if href:
self.links.append(href)
g = LinkGrabber()
g.feed(page)
print('Найдено ссылок:', len(g.links))
for href in g.links:
print(' ', href)Когда уместны регулярные выражения
Регулярки (re) хороши для поиска плоских шаблонов внутри текста: e-mail, телефоны, цены, даты. Они плохи для разбора вложенной структуры HTML, но отлично дополняют парсер на этапе «чистки» уже извлечённого текста. Достанем все e-mail из текста:
Попробуй сам ▶
import re
text = 'Пишите на [email protected] или [email protected], спам на [email protected]'
pattern = r'[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}'
emails = re.findall(pattern, text)
print('e-mail на странице:')
for e in sorted(set(emails)):
print(' ', e)Как работает под капотом
re.findall сканирует строку и возвращает все непересекающиеся совпадения шаблона. Шаблон e-mail читается так: «один или больше допустимых символов, затем @, затем домен, точка и зона из 2+ букв». Важно понимать: регулярка ничего не знает о тегах и вложенности — она видит только плоский текст.
Очистка и нормализация текста
Текст, извлечённый из HTML, почти всегда «грязный»: переводы строк, неразрывные пробелы, табуляции, лишние отступы из вёрстки. Прежде чем сохранять значение, его нормализуют. Базовый набор приёмов — strip() убирает крайние пробелы, ' '.join(text.split()) схлопывает любые пробельные последовательности в один пробел, а re.sub вычищает всё лишнее по шаблону. Для цен и чисел отдельно оставляют только цифры и приводят к int или float.
Стандартная библиотека сильнее, чем кажется. Модуль html умеет раскодировать HTML-сущности: html.unescape('&nbsp;') превратит закодированные символы обратно в нормальные. Модуль unicodedata помогает с экзотическими пробелами и диакритикой. Связка «парсер достаёт фрагмент → re и строковые методы чистят его → приведение типа» закрывает подавляющее большинство задач извлечения, не требуя ни одной внешней зависимости.
Частые ошибки
- Парсить вложенный HTML регуляркой. Классический антипаттерн: попытка вытащить содержимое тегов регуляркой ломается на любой нестандартной разметке.
- Жадные квантификаторы.
.*может «съесть» слишком много — используй нежадные.*?или точные классы символов. - Не дедуплицировать. Один e-mail может встретиться многократно —
set()убирает дубли.
Best practices
- Регулярки — для плоских шаблонов в тексте; структуру HTML разбирай парсером.
- Тестируй шаблон на реальных и «грязных» данных, а не только на идеальном примере.
- Комбинируй: парсер достаёт нужный блок, регулярка чистит и валидирует значение внутри.
Хорошая дисциплина — отделять извлечение от валидации. Сначала достаём кандидата (например, строку, похожую на цену), затем отдельно проверяем его регуляркой или приведением типа и решаем, что делать с «битыми» значениями: пропустить, записать None или залогировать. На реальных страницах всегда найдётся карточка-исключение, и устойчивый скрейпер не падает на ней, а аккуратно её обрабатывает. Такой подход — «извлёк, проверил, нормализовал» — делает результат предсказуемым даже на грязных и неоднородных данных.
Итог: стандартные html.parser и re решают много задач без внешних зависимостей. Парсер — для структуры, регулярки — для плоских шаблонов. Это фундамент, на котором стоят большие библиотеки.