Содержание урока · 10 разделов
Go стоит, терминал открыт, и на столе задача из первого урока: вытащить данные с сайта. Для тренировки берём quotes.toscrape.com — песочницу, которую специально держат для обучения скрапингу: список цитат с авторами и тегами, десять штук на страницу, разметка простая и стабильная. Цель этого урока скромная и конкретная: программа, которая скачивает страницу и печатает в терминал каждую цитату. Задача на вид маленькая, но за ней стоит весь каркас: подключение библиотеки к модулю, создание коллектора, правило, по которому colly находит нужные узлы, и запуск обхода. Всё остальное в курсе — вариации этого же скелета: другие селекторы, больше страниц, задержки, повторы, прокси. Поэтому первый скрапер стоит не пропустить, а разобрать построчно — так, чтобы каждая строка была объяснима, а не скопирована из устаревшего туториала. Запускать будем локально: скрапер ходит по сети, и песочница в браузере ему не помощник; если Go ещё не стоит, урок об установке из базового курса закроет вопрос за те же десять минут.
go mod init и go get: подключаем colly/v2#
Начало стандартное для любого Go-проекта со внешними зависимостями. В пустой папке создаём модуль: go mod init example.com/scraper — имя модуля может быть любым, для локальных упражнений хватает домена-заглушки. Затем добавляем зависимость: go get github.com/gocolly/colly/v2 — и go подкачивает библиотеку, записывая её в go.mod. Обратите внимание на хвост /v2: в Go-модулях второй мажор версии обязан жить в пути импорта, это не украшение, а часть адреса пакета. В коде импорт будет выглядеть как import "github.com/gocolly/colly/v2", и всё, что вы объявляете дальше, — colly.NewCollector, colly.HTMLElement — приходит именно оттуда. Команда go get сама выберет свежий релиз второй версии; первая версия с путём без /v2 существует отдельно, заморожена в прошлом и мы её не касаемся. Если после установки открыть go.mod, там появится строка require github.com/gocolly/colly/v2 с номером версии — это и есть фиксация зависимости, которую видят все, кто соберёт ваш проект. Рядом появится go.sum с контрольными суммами: благодаря ей сборка на другой машине получит ровно те же байты библиотеки, что и у вас, а не что-то похожее по названию.
Первый скрапер целиком
GOpackage main
import (
"fmt"
"github.com/gocolly/colly/v2"
)
func main() {
c := colly.NewCollector()
c.OnHTML("span.text", func(e *colly.HTMLElement) {
fmt.Println(e.Text)
})
err := c.Visit("https://quotes.toscrape.com/")
if err != nil {
fmt.Println("не удалось открыть сайт:", err)
}
}Вся программа — создание коллектора, одно правило и один запрос. NewCollector возвращает *colly.Collector с настройками по умолчанию; OnHTML регистрирует функцию для узлов span.text; Visit скачивает страницу, разбирает её и запускает ваши колбэки. После go get зависимость программа компилируется как есть — запустите и посмотрите на десять цитат в терминале.
Построчный разбор: NewCollector, OnHTML, Visit#
Три вызова — три разных роли. colly.NewCollector создаёт коллектор: объект, который ведёт очередь адресов, держит настройки — домены, глубину, лимиты — и хранит зарегистрированные правила. Пока он создан с нулём аргументов: дефолтов для тренировочной страницы хватает. c.OnHTML("span.text", функция) — главное правило скрапера: когда ответ скачан и разобран, colly ищет в DOM все элементы, подходящие под селектор span.text, и для каждого вызывает вашу функцию, передавая элемент обёрткой *colly.HTMLElement. У обёртки есть всё, что нужно для извлечения данных: e.Text отдаёт текст узла уже без тегов, e.Attr достаёт атрибут, а вложенные поиски мы разберём в уроках про извлечение данных. Наконец, c.Visit(url) — точка запуска: синхронный запрос, загрузка ответа, разбор в DOM и прогон всех правил. Пока Visit выполняется, программа занята; закончится обход — закончится и работа. Такая синхронность — удобный дефолт для отладки: вывод появляется предсказуемо, и рассуждать о нём легко. Кавычки, в которые обёрнута каждая цитата, — часть текста на сайте, поэтому в выводе они приедут вместе с содержимым.
Второе правило: вытаскиваем авторов#
Правил у одного коллектора может быть сколько угодно, и каждое смотрит в свой селектор. Добавим второе: рядом с каждой цитатой на странице стоит small.author с именем автора, и селектор .author ловит его по классу. Регистрируем по тому же образцу — c.OnHTML(".author", ...) и внутри печатаем e.Text — и получаем вывод, где после каждой цитаты стоит её автор. Здесь важно не спешить со следующим шагом: два независимых правила дают два независимых потока значений, и связать конкретную цитату с конкретным автором по номеру вызова — ненадёжная идея. Правильный приём — вложенный обход от контейнера цитаты, который мы разберём в уроке про механику OnHTML, а все способы достать значение из элемента собраны в уроке про Text, Attr и ChildText. Сейчас достаточно того, что вы поняли сам механизм: правило — это пара «селектор плюс функция», и функций может быть столько, сколько полей вы собираете. Попробуйте сразу добавить третье правило для a.tag — тегов цитаты, — и убедитесь, что третьим потоком всё работает точно так же: это займёт минуту и закрепит регистрацию правил лучше любого перечитывания.
Самая частая ошибка первых минут — импорт github.com/gocolly/colly без /v2. Это другой пакет первой версии: компилятор выдаёт тёмные ошибки вроде undefined: colly.HTMLElement или несовпадения типов в колбэках, а человек тратит вечер на охоту за призраком. Лечение одно: путь импорта github.com/gocolly/colly/v2 и свежая запись в go.mod. Проверяйте первую строку import до того, как гуглить ошибку.
Что именно появилось в терминале#
Полезно остановиться и рассмотреть вывод, потому что он показывает работу всей цепочки. Десять строк — по числу цитат на странице, причём порядок строк повторяет порядок цитат в разметке: colly идёт по DOM сверху вниз, и колбэк получает элементы в том же порядке. Каждая строка — чистый текст узла span.text: никаких HTML-тегов внутри, потому что e.Text возвращает текстовое содержимое, а не сырую разметку. Зато кавычки в начале и конце строки — часть данных: сайт оборачивает каждую цитату в кавычки прямо в тексте, и скрапер честно привозит их вместе со смыслом; обрезать их при желании можно обычным strings.Trim, но это уже вопрос парсинга, а не скачивания. Если вы вместо цитат увидели пустоту — программа всё равно сработала правильно: значит, промахнулся селектор, и следующая пара уроков про HTML и селекторы создана ровно для этого случая. И последнее: одна страница — это десять цитат из сорока, которые есть на сайте; до остальных мы доберёмся, когда научимся ходить по пагинации, а пока навык зафиксирован на компактном материале.
Visit возвращает ошибку, и её стоит проверить#
c.Visit(url) возвращает error, и это не формальность: сеть обрывается, домен опечатан, сервер отдаёт 404 или таймаут. В минимальном примере достаточно напечатать ошибку и выйти — как в программе выше. Но у ошибки есть и второй потребители: colly регистрирует колбэк OnError, который получает ответ и ошибку для каждого неудавшегося запроса, — туда переезжает логирование и решение, что делать дальше: повторить, пропустить адрес или остановить сбор. Полная обработка ошибок — тема отдельного урока про OnError и повторы; здесь зафиксируем привычку: любой Visit в коде курса сопровождается проверкой возвращаемого значения, потому что скрапер без неё молча рапортует об успехе на пустом выводе. Да и в бытовом смысле сообщение не удалось открыть сайт: dial tcp: no such host сэкономит вам десять минут взгляда в терминал вместо допроса селекторов, которые тут ни при чём.
Чек-лист перед запуском#
- в go.mod появилась запись require github.com/gocolly/colly/v2
- путь импорта в файле — github.com/gocolly/colly/v2, без хвоста /v2 только у первой версии
- функция OnHTML зарегистрирована до вызова Visit
- селектор скопирован с живой страницы, а не придуман по памяти
- ошибка Visit проверяется, а не отбрасывается подчёркиванием
- терминал открыт рядом: первый запуск надо видеть глазами
- вы знаете, что должно появиться в выводе: догадка про десять строк — уже тест
Проверка: путь импорта
Какой импорт правильный для второй версии colly?
Проверка: когда срабатывает правило
Колбэк из OnHTML("span.text") вызывается…
Правило, зарегистрированное поздно
Прочитайте код и выберите, что он выведет:
c := colly.NewCollector()
err := c.Visit("https://quotes.toscrape.com/")
if err != nil {
fmt.Println(err)
}
c.OnHTML("span.text", func(e *colly.HTMLElement) {
fmt.Println(e.Text)
})Восстановите второй скрапер
Допишите программу: версия в пути импорта, создание коллектора, селектор авторов и адрес страницы.
Соберите первый скрапер по строкам
Расставьте строки в правильном порядке: от объявления пакета до проверки ошибки Visit.
Строки
Ваша программа
Нажимайте на строки слева, чтобы собрать программу
Карточки: каркас colly
Что дальше#
Первый скрапер работает, но пока мы знаем про разметку ровно то, что подсказала задача со стороны: span.text и .author. Следующий урок закрывает пробел — HTML для скрапера: как читать дерево документа и находить селекторы самому. Потом — CSS-селекторы в colly во всей красе: классы, вложенность, атрибуты. А если хочется сразу к механике — пятый урок разбирает, как именно OnHTML обходит страницу и почему правил у коллектора может быть много.
Код этого урока запускается только локально: скраперу нужна сеть, которой у браузерного интерпретатора нет. Порядок простой: mkdir папка, go mod init, go get github.com/gocolly/colly/v2, go run main.go — и десять цитат в терминале.
Песочница урока
Редактируйте код и запускайте его прямо здесь — интерпретатор работает в браузере, ничего устанавливать не нужно. За каждый запуск — +2 XP.
Запустите код, чтобы увидеть вывод.
Коротко: что запомнить
- Подключение colly: go mod init в папке проекта, затем go get github.com/gocolly/colly/v2 — хвост /v2 обязателен в пути импорта.
- Скелет скрапера: NewCollector, правила OnHTML, запуск Visit — всё остальное в курсе вариации этого каркаса.
- OnHTML — пара «селектор плюс функция»: colly вызывает функцию на каждый элемент, найденный в разобранном ответе.
- Правил у коллектора сколько угодно, но регистрируют их до Visit: правило, добавленное после загрузки страницы, опоздало.
- Visit возвращает error — проверка обязательна, иначе неудачный запуск выглядит как успех с пустым выводом.
- Импорт v1-пути github.com/gocolly/colly даёт тёмные ошибки компиляции — проверяйте первую строку import.
- e.Text отдаёт текст узла без тегов; способы достать данные разобраны в шестом уроке.
Домашнее задание
Повторите установку с нуля в новой папке: go mod init, go get github.com/gocolly/colly/v2, программа из урока. Потом усложните: добавьте второе правило OnHTML для .author и третье для a.tag — тегов цитаты. Запустите и посмотрите на порядок вывода. Сознательно поменяйте импорт на путь без /v2, соберите проект, прочитайте ошибки компилятора и верните v2 обратно — умение распознавать эту ошибку по первым строкам вывода экономит вечер в будущем.
Личные заметкиПусто
Вопросы и ответы по уроку
Какая версия colly сейчас актуальна?
Вторая: путь импорта github.com/gocolly/colly/v2. Первая версия живёт по пути без /v2, заморожена и в новые проекты не берётся. go get сам подтянет свежий релиз второй версии.
Почему Visit ничего не напечатал, хотя сайт открывается?
Проверьте три вещи: правило зарегистрировано до Visit, селектор совпадает с реальной разметкой (проверьте во вкладке Elements), а e.Text выводится внутри колбэка. И убедитесь, что ошибка Visit не отброшена подчёркиванием.
Нужно ли закрывать коллектор или освобождать ресурсы?
Нет: коллектор — обычный объект Go, сборщик мусора приберёт его после выхода из программы. Close-подобных методов у него нет; единственное, о чём стоит помнить, — про Wait при асинхронном режиме, о нём отдельный урок про параллельный скрапинг.
Термины урока
Ключевые понятия из этого урока — короткие определения в глоссарии. Наведите на термин, чтобы вспомнить, откройте карточку для подробностей и ссылки на практику.
Изучайте дальше
Следующая ступень учебного пути
Testify: тестирование Go с assert и require
Интерактивный курс Testify для Go: assert и require, табличные тесты, suite, mock-объекты, Eventually, HTTP-тесты. 25 уроков с примерами и практикой в браузере.
- Писать читаемые проверки через assert и require, а не лестницы if
- Проверять ошибки, паники и краевые случаи без ручного кода
- Сравнивать структуры, слайсы, карты и числа с плавающей точкой
- Строить табличные тесты и сьюты с хуками подготовки