Структура HTML и DOM-дерево

HTML — это дерево вложенных тегов, и скрейпинг — это навигация по этому дереву.
HTML-документ — это иерархия элементов (тегов). Каждый тег может содержать атрибуты, текст и другие вложенные теги. Браузер и парсер строят из этой иерархии дерево — DOM.

Чтобы вытащить из страницы цену или заголовок, нужно понимать, где именно они лежат в структуре документа. HTML устроен как матрёшка: внешние теги содержат внутренние. Разберём простую страницу.

<html>
  <body>
    <div class="product">
      <h2 class="title">Ноутбук Pro</h2>
      <span class="price">79990</span>
      <a href="/buy/123">Купить</a>
    </div>
  </body>
</html>

Здесь div с классом product — контейнер. Внутри него — заголовок, цена и ссылка. Атрибут class="price" — это «адрес», по которому парсер найдёт цену. Атрибут href у ссылки хранит URL. Именно по тегам, классам и атрибутам скрейпер ориентируется на странице.

DOM-дерево

Парсер превращает плоский текст в дерево. Каждый тег — это узел; вложенные теги — его дети.

  html
   └── body
        └── div.product
             ├── h2.title   -> «Ноутбук Pro»
             ├── span.price -> «79990»
             └── a[href=/buy/123] -> «Купить»

Навигация по этому дереву — суть парсинга. «Найди div с классом product, внутри него возьми текст у span.price» — типичная инструкция скрейпера.

Как работает под капотом

В стандартной библиотеке Python есть модуль html.parser — простой потоковый парсер, который работает в браузере без установки чего-либо. Он не строит дерево сам, а вызывает методы-обработчики на каждый открывающий тег. Посмотрим, как он видит наш HTML:

Попробуй сам ▶

from html.parser import HTMLParser

page = '''
<div class="product">
  <h2 class="title">Ноутбук Pro</h2>
  <span class="price">79990</span>
  <a href="/buy/123">Купить</a>
</div>
'''

class Reader(HTMLParser):
    def handle_starttag(self, tag, attrs):
        print('тег <%s>  атрибуты: %s' % (tag, dict(attrs)))
    def handle_data(self, data):
        t = data.strip()
        if t:
            print('   текст:', t)

Reader().feed(page)

Видно, как парсер по очереди встречает каждый тег, читает его атрибуты и текст. Высокоуровневые библиотеки вроде BeautifulSoup строят на этом удобное дерево с поиском — но принцип внутри тот же.

Атрибуты как опора скрейпера

Главная практическая ценность для скрейпера — атрибуты тегов. class и id придуманы для стилизации и скриптов, но именно они служат «адресами» при извлечении данных: верстальщик пометил цену классом price — и ты цепляешься за этот класс. Атрибуты data-* (например, data-product-id) часто хранят чистые машинные значения, удобнее видимого текста. А href и src несут ссылки и адреса картинок, которые нужны для обхода и скачивания.

Важно понимать, насколько разметка хрупка. Один и тот же текст можно сверстать десятком способов, и при редизайне классы меняются — поэтому скрейпер всегда чуть «привязан» к конкретной версии сайта и периодически ломается. Это нормально: устойчивость повышают, выбирая самые осмысленные и стабильные зацепки (семантические классы, id, data-*) и избегая привязки к позиции элемента. Хороший скрейпер пишут так, чтобы при поломке было легко понять, какой именно селектор «поехал», и быстро его поправить.

Частые ошибки

  • Парсить HTML регулярками «вслепую». HTML вложенный и нерегулярный — для надёжного разбора нужен парсер дерева, а не только re.
  • Привязываться к хрупким путям. Если зацепиться за «третий div сверху», любой редизайн всё сломает. Лучше цепляться за классы и осмысленные атрибуты.
  • Забывать, что классов может быть несколько. class="price big sale" — это три класса сразу.

Best practices

  • Изучай структуру страницы через «Инспектор» в браузере (F12) перед написанием кода.
  • Ищи устойчивые «зацепки»: id, осмысленные class, атрибуты data-*.
  • Для серьёзного разбора используй парсер дерева (BeautifulSoup, lxml), а не только регулярки.

Освой инспектор браузера как главный рабочий инструмент исследования страницы. По F12 открывается панель разработчика; во вкладке Elements можно навести курсор на любой кусок страницы и сразу увидеть его тег, классы и положение в дереве, а правый клик «Copy → Copy selector» подскажет готовый CSS-селектор. Это превращает написание скрейпера из угадывания в точную работу: ты буквально показываешь браузеру нужный элемент и читаешь его «адрес». Привычка сначала изучить структуру в инспекторе, а потом писать код экономит massу времени.

Итог: HTML — это дерево тегов с атрибутами. Скрейпинг сводится к навигации по этому дереву и извлечению текста и атрибутов из нужных узлов. Стандартный html.parser показывает механику изнутри.

Проверьте себя
1. Что такое DOM-дерево применительно к HTML-странице?
AСписок всех ссылок на странице
BИерархия элементов, где вложенные теги являются детьми внешних
CФайл стилей CSS
DБаза данных сайта
2. Почему разбирать сложный HTML одними регулярными выражениями — плохая идея?
AРегулярки работают только с числами
BHTML вложенный и нерегулярный, поэтому надёжнее парсер дерева
CРегулярки запрещены законом
DЭто всегда работает идеально