Перейти к содержимому
ГоМастер

Поиск по урокам

Найдите урок, курс, термин или раздел

Урок 4 из 25 ~18 мин +50 XP

CSS-селекторы в Colly: от тегов до комбинаций

CSS-селекторы — язык запросов к дереву страницы, и в colly он живёт внутри OnHTML: одна строка решает, какие узлы увидит ваш колбэк, а какие пройдут мимо. Разберём формы от простого тега до комбинаций с атрибутами и псевдоклассами, соберём таблицу «что выбирает — когда использовать» и научимся балансировать между точностью и устойчивостью.

Содержание урока · 11 разделов

Ситуация, знакомая каждому первому вечеру со скрапером: во вкладке Elements вы глазами нашли нужный элемент, написали селектор по памяти — и получили либо пустоту, либо полстраницы лишнего. Дело не в colly и не в сайте, а в том, что селектор — это точный запрос к дереву, а не описание «где примерно лежит текст». Хорошая новость: язык маленький. Пара десятков форм покрывает все задачи скрапинга, и в этом уроке мы разберём их на двух песочницах — цитатах и книжном каталоге books.toscrape.com. Каждый селектор ниже можно проверить руками: поиском по документу в devtools, а потом в настоящей программе. К концу урока у вас будет внутренняя таблица соответствий: вот это — для повторяющихся карточек, вот это — для единственного блока, вот это — для ссылок, отфильтрованных по адресу. И второе умение, не менее важное: понимать, когда селектор слишком умный и сломается при следующем релизе сайта. Примеры урока, как и везде в курсе, запускаются локально: скраперу нужна сеть, которой у браузерной песочницы нет, — а вот проверять селекторы в devtools можно прямо сейчас.

Три простые формы: тег, класс, идентификатор#

Базовые формы вы уже видели в прошлых уроках. Селектор-тег — span, a, h1 — выбирает все узлы с таким тегом: span.text на странице цитат поймает и тексты, но вместе с ними и служебные span, поэтому тегом пользуются как частью более длинных запросов. Селектор-класс начинается с точки: .price_color собирает все элементы с классом price_color — на books.toscrape.com это цены всех двадцати книг страницы. Селектор-идентификатор начинается с решётки: #content — единственный узел с таким id, главный контейнер страницы. Colly передаёт строку селектора в goquery, тот компилирует её и ищет совпадения в DOM-дереве ответа — вы пишете обычный CSS, никаких особых диалектов. На практике выбор формы простой: класс — рабочая лошадка для повторяющихся данных, идентификатор — редкая роскошь привязки к конкретному блоку, тег в одиночку — почти всегда слишком широкая сеть. Комбинация из двух-трёх форм — article.product_pod, div.quote, li.next a — закрывает большинство селекторных задач каталогов.

Три правила на книжном каталоге

GO
c := colly.NewCollector()

c.OnHTML(".price_color", func(e *colly.HTMLElement) {
        fmt.Println("цена:", e.Text)
})

c.OnHTML("article.product_pod h3 a", func(e *colly.HTMLElement) {
        fmt.Println("название:", e.Attr("title"))
})

err := c.Visit("http://books.toscrape.com/")

Первое правило берёт цены по классу: .price_color стоит ровно у тех узлов, где живёт цена. Второе поднимается от карточки article.product_pod к заголовку и ссылке внутри — а значение берёт из атрибута title, потому что в тексте ссылки название обрезано. Два правила работают независимо и печатают по двадцать значений каждый.

Потомок и прямая вложенность: пробел против угловой скобки#

Комбинатор — то, что стоит между двумя простыми селекторами, — и он же источник половины ошибок. Пробел означает любого потомка на любой глубине: article.product_pod a находит все ссылки внутри карточки, и те, что лежат сразу в ней, и те, что спрятаны в h3 или image_container. Угловая скобка — прямого ребёнка: article.product_pod > a найдёт только ссылки, лежащие непосредственно внутри карточки, без одного уровня вложенности — и на books.toscrape.com их не окажется, потому что ссылки спрятаны внутри h3 и div. Выбор между ними — вопрос глубины, в которой вы уверены. Пробел устойчив к мелким перестройкам разметки: вставьте сайт ещё один обёрточный div, и селектор с пробелом продолжит работать, а со скобкой — отвалится. Зато скобка защищает от ложных совпадений, когда целевой тег встречается и в карточке, и глубже внутри вложенного блока. Практическое правило: пока не нарвались на ложные совпадения, пишите пробел; скобку добавляйте, когда без неё селектор ловит лишнее.

Атрибутные селекторы: фильтр по значению#

Когда классов не хватает, включаются атрибуты. Форма [attr] выбирает узлы, у которых атрибут есть вовсе: [data-id] — все элементы с data-id. Форма [attr=value] требует точное значение: input[type="text"] — только текстовые поля. Для скрапинга самой полезной оказалась частичная проверка: [attr^=value] — значение начинается с префикса. На books.toscrape.com ссылки каталога ведут на адреса вида catalogue/page-2.html и catalogue/mediocre-xxx/index.html, и селектор a[href^="/catalogue/"] ловит только внутренние ссылки каталога, отсекая навигацию и внешние адреса — готовый фильтр для обхода, которому не нужен никакой код. Обратный префикс — [attr$=value]: img[src$=".jpg"] выбирает картинки по расширению. Атрибуты также спасают там, где классы сгенерированы сборкой: href, src, title, data-* обычно стабильнее имён классов, потому что отвечают за поведение, а не за оформление. Единственная цена — чуть более многословная строка, зато селектор читается как условие на естественном языке.

Псевдоклассы: nth-of-type и first-of-type#

Псевдоклассы описывают положение узла среди соседей. li:nth-of-type(2) выбирает второй элемент li среди однотипных соседей внутри родителя — счёт ведётся с единицы, а не с нуля, и это привычная ловушка для тех, кто пришёл из индексов Go. :first-of-type берёт первый однотипный узел, :last-of-type — последний. В скрапинге они нужны нечасто, но когда нужны — спасают полностью: колонка «второй столбец каждой строки таблицы», первый абзац карточки, второй div в блоке без классов. Две оговорки. Первая: of-type считает узлы одного тега, а не одного класса — .price:nth-of-type(2) означает «второй элемент своего тега, если у него есть класс price», и это не то же самое, что «второй price». Вторая: псевдоклассы жестоко завязаны на порядок соседей, а порядок — любимая вещь дизайнеров для перестановок. Если задачу можно решить без нумерации — контейнером, классом, атрибутом — решайте без неё; nth-of-type оставьте для случаев, когда у узла буквально нет других примет.

Селектор — что выбирает — когда использовать#

СелекторЧто выбираетКогда использовать
spanвсе span на страницевнутри более длинных комбинаций, редко один
.price_colorвсе узлы с этим классомповторяющиеся данные: карточки, цены, строки
#contentединственный узел с этим idпривязка к главному блоку страницы
.quote spanлюбые span внутри .quote на любой глубинедефолт для вложенности
.quote > spanтолько span — прямые дети .quoteкогда пробел ловит лишнее из глубины
a[href^="/catalogue/"]ссылки, ведущие внутрь каталогафильтрация ссылок для обхода без кода
img[src$=".jpg"]картинки с таким расширениемвыкачивание файлов по типу
li:nth-of-type(2)второй li среди соседей своего тегаположение без классов; счёт с единицы

Что именно поддерживает colly: базовое подмножество CSS3#

Селекторы в OnHTML — это CSS3 в исполнении goquery, библиотеки разбора HTML, на которой colly собирает DOM и компилирует запросы. Говоря точнее: colly умеет базовое подмножество CSS3 — теги, классы, идентификаторы, комбинаторы вложенности, атрибутные условия и распространённые псевдоклассы. Экзотика современных браузеров и редкие псевдоклассы в этой реализации не гарантируются, и перечислять «что сломано» по памяти опасно: поведение зависит от версии библиотеки, а гугл-выдержки легко устаревают. Рабочая тактика практичнее: селектор сначала проверяется на живой странице поиском по документу в devtools, потом — в программе. Совпало в браузере, но не совпало в colly — значит, форма не из поддерживаемого подмножества, и её переписывают через базовые формы: иногда достаточно разбить один хитрый селектор на два правила OnHTML и связать их вложенным обходом, о котором пойдёт речь в следующем уроке. Так вы никогда не застрянете: базовое подмножество закрывает девять задач из десяти.

Правила устойчивого селектора#

  • самая короткая комбинация, которая однозначно определяет данные, — лучше всего контейнер плюс цель
  • семантические теги и осмысленные классы вместо позиционных номеров детей
  • атрибуты href, src, data-* вместо хэшированных имён классов
  • nth-of-type — только когда у узла нет других примет
  • селектор проверен на второй и последней странице каталога, а не только на первой
  • в коде есть реакция на ноль найденных элементов

Проверка: пробел или скобка

Чем селектор .quote > span отличается от .quote span?

Проверка: атрибутный префикс

Что выберет селектор a[href^="/catalogue/"] на books.toscrape.com?

Сколько узлов соберёт селектор

Прочитайте код и выберите, что он выведет:

<div class="quote">
  <span class="text">"Quote text here."</span>
  <span>by <small class="author">Jane Austen</small></span>
  <div class="tags">
    <a class="tag" href="/tag/truth/">truth</a>
  </div>
</div>

// Селектор: .quote span
// Вопрос: сколько вызовов колбэка даст OnHTML(".quote span")?

Восстановите селекторы книжного скрапера

Допишите правила: класс цены, путь от карточки к ссылке заголовка и фильтр ссылок пагинации по началу адреса.

c := colly.NewCollector() c.OnHTML("", func(e *colly.HTMLElement) { fmt.Println("цена:", e.Text) }) c.OnHTML("article.product_pod h3 ", func(e *colly.HTMLElement) { fmt.Println("название:", e.Attr("title")) }) c.OnHTML("[href="/catalogue/"]", func(e *colly.HTMLElement) { fmt.Println("ссылка:", e.Attr("href")) })

Соберите скрапер с двумя правилами

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

Строки

Ваша программа

Нажимайте на строки слева, чтобы собрать программу

Карточки: язык селекторов

Термин

.class

нажмите, чтобы перевернуть
Определение

Все узлы с этим классом; классы носят сколько угодно элементов — основа выборки повторяющихся данных.

1 / 6

Что дальше#

Селекторы отвечают на вопрос «что искать», но не рассказывают, как colly их выполняет. Следующий урок — механика OnHTML: сколько раз вызовется колбэк, в каком порядке срабатывают правила и как связывать вложенные выборки через ForEach. Потом — способы достать значение: e.Text, e.Attr и семейство Child-методов, которые добирают данные из глубины выбранного узла. А разобранная здесь разметка цитат пригодится в каждом из них.

Песочница урока

Редактируйте код и запускайте его прямо здесь — интерпретатор работает в браузере, ничего устанавливать не нужно. За каждый запуск — +2 XP.

Вывод

Запустите код, чтобы увидеть вывод.

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

  • Селектор — точный запрос к DOM-дереву; colly передаёт строку в goquery, который компилирует её и находит узлы.
  • Три простые формы: тег для длинных комбинаций, .class для повторяющихся данных, #id для единственного блока.
  • Пробел — любой потомок, угловая скобка — прямой ребёнок; по умолчанию пишут пробел, скобку добавляют против ложных совпадений.
  • Атрибутные формы [attr], [attr=value], [attr^=value], [attr$=value] фильтруют ссылки и картинки по адресам без кода.
  • Псевдоклассы nth-of-type и first-of-type описывают положение среди соседей; счёт с единицы и крайнее средство по устойчивости.
  • colly поддерживает базовое подмножество CSS3 через goquery; экзотику проверяют на живой странице и переписывают базовыми формами.
  • Длинные селекторы-паровозы умирают молча при чужом релизе: самая короткая однозначная комбинация плюс реакция на ноль совпадений.

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

На books.toscrape.com соберите три правила OnHTML: цены всех книг страницы, полные названия из атрибута title ссылок в h3 и ссылки пагинации из li.next. Потом сломайте свой селектор специально: замените .price_color на div.row и посмотрите, что окажется в выводе. После этого возьмите Copy selector на карточке товара и сократите его минимум вдвое без потери набора совпадений — проверяйте поиском по документу.

Личные заметкиПусто
Хранятся только в вашем браузере (Colly · CSS-селекторы в Colly: от тегов до комбинаций)

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

Какие CSS-селекторы поддерживает colly?

Базовое подмножество CSS3 через goquery: теги, классы, идентификаторы, комбинаторы пробела и скобки, атрибутные условия и распространённые псевдоклассы вроде nth-of-type. Экзотические формы проверяют на живой странице; если не сработало — переписывают базовыми формами.

Почему селектор из devtools в colly не находит элементы?

Copy selector выдаёт абсолютный путь с номерами детей (nth-child), который считает положение блока на конкретной странице. Он ломается при любом изменении разметки. Сократите путь до повторяющейся части — контейнер плюс цель.

Скобка или пробел — что лучше?

По умолчанию пробел: он выживает при появлении новых обёрточных div. Угловую скобку берут, когда пробел ловит лишнее из глубины карточки — например, одноимённые элементы в подвале блока. Выбор всегда проверяют на второй странице каталога.

Термины курса

Понятия, на которых строится этот курс, — короткие определения в глоссарии. Наведите на термин, чтобы вспомнить, откройте карточку для подробностей и ссылок на практику.

Следующая ступень учебного пути

Testify25 уроков~9 чпрактика25 уроков уже доступны

Testify: тестирование Go с assert и require

Интерактивный курс Testify для Go: assert и require, табличные тесты, suite, mock-объекты, Eventually, HTTP-тесты. 25 уроков с примерами и практикой в браузере.

  • Писать читаемые проверки через assert и require, а не лестницы if
  • Проверять ошибки, паники и краевые случаи без ручного кода
  • Сравнивать структуры, слайсы, карты и числа с плавающей точкой
  • Строить табличные тесты и сьюты с хуками подготовки