---
title: "HTML для скрапера: DOM, теги, атрибуты"
description: "HTML для парсинга: dom дерево страницы, теги и атрибуты, классы против id, data-атрибуты, вкладка Elements в devtools и разбор разметки quotes.toscrape."
course: "Colly: парсинг и веб-скрапинг на Go"
url: "https://golangmaster.ru/courses/colly/lessons/03-html-dlya-skrepera/"
published: "2026-09-19"
updated: "2026-09-21"
minutes: 16
---

# HTML для скрапера: DOM, теги, атрибуты

*Курс «Colly: парсинг и веб-скрапинг на Go», урок 3 из 25. ~16 минут. Обновлено 21.09.2026. Источник: https://golangmaster.ru/courses/colly/lessons/03-html-dlya-skrepera/*

HTML для парсинга — это не вёрстка, а карта местности: скраперу достаточно уметь читать дерево документа, различать классы, id и атрибуты, чтобы находить данные по селекторам. В этом уроке доберём этот минимум: разберём DOM на разметке quotes.toscrape, научимся работать с вкладкой Elements и поговорим о разметке, которая переживает чужие релизы.

Вы открываете вкладку Elements в браузере, и на вас вываливается четыре тысячи строк разметки: вложенные div, классы-абракадабра, скрипты, мета-теги. Хочется закрыть и попросить кого-то другого. Хорошая новость: скраперу вёрстка нужна ровно в объёме, которого хватает, чтобы найти данные и не потерять их завтра. Вы не собираетесь править CSS и ловить баги отступов — вы ищете контейнеры, тексты и атрибуты, и на это уходит процентов двадцать языка. Уверенно читать дерево документа, понимать, чем класс отличается от идентификатора и зачем нужны data-атрибуты, — этого достаточно, чтобы писать селекторы для девяти задач из десяти. Остальная глубина — для верстальщиков, и она нам не пригодится. Всё, что ниже, разбирается на живой разметке песочницы quotes.toscrape.com: откройте её в соседней вкладке и проверяйте каждое утверждение глазами. Программных примеров в этом уроке почти нет — зато весь материал сразу ложится в скрапер из второго урока, когда вы запустите его локально с новым селектором.

### DOM: дерево страницы, по которому ходит скрапер

Браузер, получив HTML, строит из него **DOM** — объектную модель документа, и dom дерево страницы — это иерархия узлов: элемент внутри элемента внутри элемента. У каждой ветки есть родитель, у элементов — дети, у текста внутри тегов — текстовые узлы. Корень дерева — html, под ним head и body, и дальше разметка разветвляется по вложенности. Скраперу это дерево важно по одной причине: селекторы в colly ищут не строки в тексте, а узлы в дереве, и результат поиска зависит от того, где именно лежит узел и кто его предки. Один и тот же span на верхнем уровне и span внутри карточки товара — разные цели для селектора. Вложенность читается по отступам в исходнике: всё, что открыто между открывающим и закрывающим тегом контейнера, — его потомки. Ошибка новичка — судить о структуре по визуальному расположению на экране: браузер растягивает и переносит элементы так, что визуально рядом могут лежать узлы из разных веток дерева. Смотрите на вложенность, а не на картинку.

### Разметка одной цитаты из quotes.toscrape

```go
<div class="quote" itemscope itemtype="http://schema.org/CreativeWork">
  <span class="text" itemprop="text">
    "The world as we have created it is a process of our thinking."
  </span>
  <span>by <small class="author" itemprop="author">Albert Einstein</small></span>
  <div class="tags">
    Tags:
    <meta class="keywords" itemprop="keywords" content="change,deep-thoughts">
    <a class="tag" href="/tag/change/page/1/">change</a>
    <a class="tag" href="/tag/deep-thoughts/page/1/">deep-thoughts</a>
  </div>
</div>
```

Типовой контейнер: div.quote обнимает всё, что относится к одной цитате; span.text несёт текст, small.author — автора, ссылки a.tag — теги. itemscope и itemprop — микроразметка schema.org: сайт помогает поисковикам, а заодно и нам. На странице таких контейнеров десять, по одному на цитату.

### Теги и атрибуты: на что смотрит скрапер

Тег задаёт тип узла — div, span, a, img, small, — а атрибуты приписаны тегу парами имя-значение. Для парсера значимы четыре вида: class и id, на которых держатся селекторы; href у ссылок и src у картинок — адреса, по которым ходит и качает скрапер; title и alt — человеческие подписи, в которых сайты любят прятать полные названия товаров; и data-атрибуты вида data-url, data-id — куда фронтенд складывает машиночитаемые значения. Текст узла — то, что лежит между открывающим и закрывающим тегом, — достаётся через e.Text, а атрибуты — через e.Attr; это два разных выхода из одного узла, и выбирать надо по тому, где данные надёжнее. Классический пример: у карточки товара в каталоге books.toscrape.com название обрезано в тексте ссылки до пары слов, а полный вариант лежит в атрибуте title той же ссылки — берут именно атрибут. Разметка обычно щедрее, чем кажется: у большинства узлов найдётся второй путь к данным.

### Класс против id: сколько элементов выбирает селектор

Класс описывает тип или роль элемента, и один класс может носить сколько угодно узлов на странице — десять карточек каталога делят один класс product_pod. Идентификатор id по стандарту должен быть уникален в документе: один узел — один id, чаще всего это главный контейнер страницы вроде id="content" или навигация. Отсюда правило выбора для скрапера: повторяющиеся данные — цитаты, товары, строки таблицы — ищут по классам, потому что их много; привязку к конкретному месту страницы делают по id, если он есть и стабильный. Жизнь вносит поправки: современные фронтенд-фреймворки генерируют id автоматически, и они меняются от сборки к сборке, а на некоторых сайтах один id тихо повторяется пять раз, потому что верстальщику было удобно. Поэтому и класс, и id стоит проверять взглядом: откройте Elements, посчитайте совпадения, пройдитесь на вторую страницу каталога и убедитесь, что селектор ловит то же самое. Проверка занимает минуту и экономит вечер отладки.

### Инлайн и внешний контент: что видит скрапер

Здесь спрятана ловушка, о которую спотыкаются все, кто привык к вкладке Elements. Скрапер получает исходный HTML-ответ сервера — то, что отдал сайт по сети, до всяких скриптов. Вкладка Elements показывает текущий DOM: после того как JavaScript успел дорисовать, переставить и удалить узлы. Для серверных страниц, как наши песочницы, разница почти нулевая. Но на сайтах с рендерингом в браузере Elements показывает данные, которых в исходном ответе нет: скрапер по селектору из Elements получит пустоту. Способ проверки без кода: правый клик по странице — «Просмотреть исходный код страницы» и поиск по тексту, который вы ищете. Нашли фрагмент в исходнике — colly до него доберётся; не нашли — данные приходят скриптом, и это уже разговор про браузерные движки из урока про [пределы colly](/courses/colly/lessons/22-antibot-zaschita/). Вторая половина той же мысли: текст, который вы видите на экране, может собираться из нескольких узлов и псевдоэлементов CSS, а e.Text берёт только то, что реально лежит в дереве.

### Data-атрибуты и семантические теги: надёжные зацепки

Хорошие сайты оставляют для машин явные зацепки, и ими стоит пользоваться в первую очередь. Data-атрибуты — всё, что начинается с data-, — придуманы для того, чтобы JavaScript носил данные прямо в разметке: data-id="42", data-url="/product/42", data-price="1490". Они почти не участвуют в оформлении, поэтому живут дольше классов; для скрапера это часто лучший источник значений. Семантические теги — article, main, nav, table, header — описывают смысл блока, а не его вид: карточка товара почти всегда article, список статей — внутри main. Селектор article.product_pod переживает редизайн чаще, чем div.row > div:nth-child(3), потому что смысл карточки не меняется вместе с сеткой раскладки. Микроразметка itemprop, как в разметке цитаты выше, — ещё один слой стабильности: сайты несут её для поисковиков и редко ломают. Приоритет простой: data-атрибуты и семантика, потом осмысленные классы, и только потом геометрия страницы.

> **Живое место: классы, склеенные сборкой.** На продакшен-сайтах классы бывают хэшированными: css-1x2abc, sc-jEABwJ, ProductCard__price--3kF9q. Их генерирует сборщик CSS-модулей, и при следующем деплое суффиксы переломаются — селектор .css-1x2abc отдаст ноль элементов, скрапер замолчит, а виноватых не найдут. Лечение: не вцепляться в хэш, а подниматься к устойчивому — семантическому тегу, data-атрибуту или стабильной части имени вроде ProductCard__price. Правило: селектор, в котором есть непроизносимая абракадабра, — селектор с датой смерти.

### Elements в devtools: от клика до селектора

Рабочий цикл скрапера начинается в браузере. Правый клик по нужному элементу на странице — «Просмотреть код» — и вкладка Elements разворачивается на том самом узле. Дальше три вопроса: что это за тег, какие у него классы и атрибуты, и что вокруг — в каком контейнере он лежит. Контейнер важнее всего: селектор, построенный от контейнера цитаты, точнее, чем селектор, построенный от самого текста. В контекстном меню узла есть Copy selector — и им стоит пользоваться с оговоркой: devtools часто выдаёт абсолютный путь вида body > div.container > div.row > div.col-md-8 > div.quote:nth-child(4) > span.text — с номерами детей, которые переломаются, как только на странице станет на одну цитату больше или меньше. Такой вариант берут как сырьё: сокращают до повторяющейся части div.quote span.text и проверяют поиском по документу, сколько узлов ловится. Самая эффективная привычка — искать по классу в поиске devtools: Ctrl+F внутри Elements показывает все совпадения и сразу даёт понять, уникален ли селектор.

### Что где лежит: карта атрибутов скрапера

| Атрибут | Что в нём | Как использовать |
| --- | --- | --- |
| class | роль элемента, обычно не уникальна | основной материал селекторов для повторяющихся данных |
| id | уникальный идентификатор узла | привязка к конкретному блоку страницы, если id стабильный |
| href, src | адреса ссылок и картинок | источник для обхода и для выкачивания файлов |
| title, alt | полные подписи элементов | полные названия, обрезанные в тексте, и описания картинок |
| data-имя | машиночитаемые значения фронтенда | часто самый стабильный путь к id, url и ценам |
| itemprop, content | микроразметка schema.org | структурированные данные, которые сайты держат для поисковиков |

### Проверка: класс и id

**Вопрос:** На странице десять карточек товара. Какой селектор их соберёт?

- #product_pod — по идентификатору
- ✅ .product_pod — по классу, который носят все десять карточек
- body — самый широкий селектор
- Селектором карточки собрать нельзя, только руками

Повторяющиеся данные ищут по классу: у всех карточек он общий, а id должен быть уникален в документе. Body тоже матчится, но один раз — на всю страницу, и данных карточки из него так просто не достать.

### Проверка: Elements против исходника

**Вопрос:** Во вкладке Elements карточка товара видна, но скрапер по селектору получает ноль элементов. Первое действие?

- Добавить задержку в код и перезапустить
- ✅ Сравнить с исходным кодом страницы: есть ли разметка в HTML-ответе сервера
- Поменять браузер
- Увеличить число OnHTML-правил

Elements показывает DOM после скриптов, а colly видит исходный HTML-ответ. Если данных в исходнике нет — их рисует JavaScript, и селектор здесь ни при чём: нужен браузерный движок или поиск JSON-эндпоинта.

### Что выберет селектор в этой ветке

```go
<div class="quote">
  <span class="text">"Be yourself; everyone else is already taken."</span>
  <span>by <small class="author">Oscar Wilde</small></span>
</div>

// Селектор: .quote .author
// Вопрос: какой текст достанет e.Text на этом элементе?
```

**Что выведет программа?**

- by Oscar Wilde — вместе со словом by
- ✅ Oscar Wilde — только содержимое узла small.author
- Пустую строку: у small нет текста
- Всю цитату целиком вместе с автором

Селектор находит узел small.author, а e.Text возвращает текст этого узла: Oscar Wilde. Слово by лежит в родительском span, вне small, поэтому в значение не попадает — дерево решает, что входит в текст.

### Соберите разметку цитаты

Допишите фрагмент разметки: класс контейнера цитаты, класс текста и класс автора — ровно как в quotes.toscrape.

```go
<div class="___">
  <span class="___">"Текст цитаты"</span>
  <small class="___">Albert Einstein</small>
</div>
```

Подсказка: Три имени, которые будут встречаться весь курс: контейнер quote, текст в span с классом text, автор в small с классом author.

Правильные ответы в пропусках: `quote`, `text`, `author`

### Соберите вложенность разметки

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

Правильный порядок строк:

1. `<div class="quote">`
2. `<div class="tags">`
3. `<a class="tag" href="/tag/change/page/1/">change</a>`
4. `</div>`
5. `<small class="author">Albert Einstein</small>`
6. `</div>`

### Карточки: HTML глазами скрапера

- **DOM** — Объектная модель документа: дерево узлов, которое браузер строит из HTML. Селекторы colly ищут узлы именно в нём.
- **class** — Роль элемента; один класс носят сколько угодно узлов. Основной материал для селекторов повторяющихся данных.
- **id** — Идентификатор, уникальный в документе по стандарту. Привязка к конкретному месту страницы — если он не генерируется сборкой.
- **data-атрибут** — Атрибут вида data-id, data-url, куда фронтенд кладёт машиночитаемые значения. Почти не связан с оформлением, поэтому стабилен.
- **Исходный код против Elements** — Исходник — HTML-ответ сервера, Elements — DOM после скриптов. Скрапер видит исходник; данные есть только в Elements — их рисует JavaScript.
- **Хэшированный класс** — Имя вроде css-1x2abc, сгенерированное CSS-модулями. Меняется при каждом деплое; скраперу нужны семантика, data-атрибуты или стабильная часть имени.

### Что дальше

Разметка прочитана, зацепки найдены — пора превращать их в запросы. Следующий урок — [CSS-селекторы в colly](/courses/colly/lessons/04-css-selektory/): от простых тегов и классов до комбинаций, атрибутных условий и псевдоклассов. А после него — пятый, про механику [колбэков OnHTML](/courses/colly/lessons/05-onhtml-kolbeki/): что именно colly делает с найденными узлами и как не намолотить дубликатов. Если захочется освежить, зачем всё это нужно и где границы темы, — вернитесь к [знакомству с Colly](/courses/colly/lessons/01-znakomstvo-colly/).

## Коротко: что запомнить

- Скраперу хватает минимума HTML: дерево документа, теги, атрибуты, текст узлов — вёрстка на этом объёме заканчивается.
- DOM — дерево вложенных узлов; селектор ловит узлы по месту в дереве, а не по внешнему виду на экране.
- Классы носят много элементов — ими собирают повторяющиеся данные; id уникален и подходит для привязки к блоку, если он стабильный.
- Важные атрибуты: href и src — адреса, title и alt — полные подписи, data-* — машиночитаемые значения, itemprop — микроразметка.
- Elements показывает DOM после скриптов, скрапер видит исходный HTML-ответ; расхождение проверяют через просмотр исходного кода.
- Хэшированные классы вроде css-1x2abc переламываются при деплое — зацепки выбирают по убыванию стабильности: data-атрибуты, семантика, осмысленные классы.
- Copy selector из devtools — сырьё, а не готовое решение: абсолютные пути с nth-child сокращают и проверяют на второй странице.

## Домашнее задание

Откройте quotes.toscrape.com и books.toscrape.com в двух вкладках devtools. Для каждой песочницы выпишите: класс контейнера повторяющегося блока, селектор текста, селектор атрибута со ссылкой и один data-атрибут или itemprop, если найдёте. Потом возьмите Copy selector на карточке товара в books и сократите его до самого короткого варианта, который ловит все карточки на странице — проверьте поиском по документу.

## Вопросы и ответы по уроку

### Насколько глубоко нужно знать HTML для парсинга?

Хватит дерева документа, тегов, атрибутов и классов: контейнер, текст, ссылка, картинка. Флексбоксы, сетки и обработчики событий — территория верстальщика; скраперу важнее уметь читать вложенность и выбирать стабильные зацепки.

### Почему Copy selector из devtools не работает в скрапере?

Работает, но недолго: devtools выдаёт абсолютный путь с номерами детей (nth-child), который переламывается при любом изменении количества блоков. Сократите путь до повторяющейся части — контейнер плюс цель — и проверьте на нескольких страницах.

### Скрапер видит страницу так же, как браузер?

Нет: он получает исходный HTML-ответ, до исполнения JavaScript. Вкладка Elements показывает уже обработанный DOM. Если данные есть только в Elements, их рисуют скрипты, и colly по ним пройдёт с пустыми руками.
