Веб-скрейпинг на Go с goquery: полное руководство

Что такое веб-скрейпинг
Веб-скрейпинг, или извлечение веб-данных, — это автоматизированный способ получения содержимого веб-страниц. Скрейперы отправляют HTTP-запросы к сайту, получают HTML и затем извлекают нужные данные программно вместо того, чтобы отображать страницу пользователю.
Коротко: отправили запрос → получили HTML → распарсили → выбрали данные → сохранили.
Важно: перед запуском скрейпинга проверьте правила сайта (robots.txt) и юридические ограничения. Технически можно собрать почти любые данные, но правовые и этические границы соблюдать нужно всегда.
Для чего это нужно
- Сбор данных для анализа и машинного обучения.
- Мониторинг цен и доступности товаров.
- Интеллектуальная собственность и исследования в кибербезопасности.
- Интеграция данных с сервисами без открытого API.
Варианты библиотек для скрейпинга на Go
- goquery — парсер HTML с API, похожим на jQuery, основан на net/html и Cascadia для селекторов CSS.
- Colly — специализированная библиотека для веб-скрейпинга с удобной архитектурой, очередями и ограничениями скорости.
- ChromeDP — драйвер, использующий Chrome DevTools Protocol; полезен для JavaScript-динамических страниц (headless Chrome).
Когда выбирать: если страница статическая — goquery быстрее и проще. Если нужна эмуляция браузера и выполнение JS — ChromeDP или Headless Chrome через Puppeteer/Playwright будут лучше. Colly хорош для распределённого или масштабного сбора.
Что такое goquery
goquery вдохновлён jQuery: он предоставляет удобные методы для навигации по дереву HTML и извлечения текста/атрибутов с помощью CSS-селекторов. Технически библиотека использует net/html для парсинга HTML5 и Cascadia для сопоставления селекторов.
Установка goquery
Откройте терминал и выполните:
go get github.com/PuerkitoBio/goqueryЕсли возникают ошибки — обновите версию Go и убедитесь, что GOPATH и модульные настройки корректны (go mod init/require).
Общая схема процесса скрейпинга
- Подготовить HTTP-запрос.
- Получить HTML-ответ.
- Распарсить HTML в документ goquery.
- Найти нужные элементы CSS-селекторами.
- Извлечь текст и атрибуты (href, src и т. п.).
- Сохранить результаты в структуру или БД.
Отправка HTTP-запроса в Go
В стандартной библиотеке есть пакет net/http. Простой пример запроса:
package main
import (
"fmt"
"log"
"net/http"
)
func main() {
webUrl := "https://news.ycombinator.com/"
response, err := http.Get(webUrl)
if err != nil {
log.Fatalln(err)
} else if response.StatusCode == 200 {
fmt.Println("We can scrape this")
} else {
log.Fatalln("Do not scrape this")
}
}http.Get возвращает *http.Response и ошибку. Проверяйте response.StatusCode — при 200 можно продолжать обработку.
Заметка: в реальном проекте используйте http.Client с таймаутами и возможностью настройки заголовков (User-Agent, cookies), чтобы снизить риск блокировок.
Парсинг HTML и получение документа goquery
После успешного запроса нужно распарсить тело ответа в документ goquery:
document, err := goquery.NewDocumentFromReader(response.Body)
if err != nil {
log.Fatalln(err)
}document представляет DOM-дерево страницы и позволяет применять CSS-селекторы.
Как выбирать элементы с помощью селекторов
Прежде чем писать код, откройте страницу в браузере и изучите структуру (DevTools). Это поможет составить точные селекторы.
Пример: найти строки с классом tr.athing:
document.Find("tr.athing")Выборка нескольких элементов и обход
Чтобы получить все совпадения, используйте Each — она перебирает найденные элементы и вызывает функцию-обработчик:
document.Find("tr.athing").Each(func(index int, selector *goquery.Selection) {
/* Обработка элемента selector */
})Внутри обработчика вы можете уточнить выборку и извлечь текст или атрибуты:
document.Find("tr.athing").Each(func(index int, selector *goquery.Selection) {
title := selector.Find("td.title").Text()
link, found := selector.Find("a.titlelink").Attr("href")
if found {
// обработать link
}
})Text() возвращает текст внутри элемента. Attr возвращает значение атрибута и булево значение, указывающее, найден ли атрибут.
Совет: используйте strings.TrimSpace для очистки текста от лишних пробелов и невидимых символов.
Пример структуры данных и сохранение
Часто достаточно пользовательского struct и среза, чтобы аккумулировать результаты. Заметьте: если вы хотите кодировать данные в JSON или экспортировать поля, имена полей должны быть экспортируемыми (начинаться с заглавной буквы).
type Information struct {
Link string
Title string
}
info := make([]Information, 0)
// Внутри Each:
// info = append(info, Information{Title: title, Link: link})
fmt.Println(info)В реальных сценариях вы будете сохранять данные в базу (Postgres, MySQL через database/sql, MongoDB через официальный драйвер или в кеш на диске). Кеширование снижает нагрузку на исходный сервер и ускоряет повторные запросы.
Кейсы и альтернативные подходы
- Статическая страница (HTML формируется на сервере): goquery + net/http — быстро и просто.
- Динамическая страница (контент формируется JS): используйте ChromeDP или внешний headless-браузер (Playwright, Puppeteer) и забирайте уже отрендеренный DOM.
- Масштабный сбор: Colly даёт встроенные механизмы ограничений скорости, очередей и параллелизации.
Контрпример: если сайт предлагает официальное API с нужными данными и ограничениями, лучше использовать API — это надежнее и легальнее.
Безопасность и этика
Важно:
- Соблюдайте robots.txt и правила сайта.
- Не отправляйте слишком много запросов за короткое время — используйте rate limiting.
- Уважайте авторские права и персональные данные.
Риск блокировок минимизируется корректной настройкой заголовков, задержек и ротацией прокси, но прокси и обход ограничений должны использоваться с юридическим обоснованием.
Принципы тестирования и критерии приёмки
Критерии приёмки:
- Скрипт корректно получает 200 OK и распарсивает документ.
- Для каждой ожидаемой записи извлекаются title и link (не пустые).
- Данные сохраняются в структуре или БД без ошибок записи.
- Скрипт выдерживает базовую ошибку сети и повторяет попытку с экспоненциальной задержкой.
Примеры тестов:
- Мокаем HTTP-ответ чартером с статическим HTML и проверяем, что срез info содержит N элементов.
- Проверяем поведение при 404/500: обработка ошибки и логирование.
Производительность и зрелость решения
Уровни зрелости:
- MVP: одиночный скрипт на goquery + net/http, сохраняющий в JSON/CSV.
- Продакшн-минимум: добавить таймауты, ретраи, логирование и конфиг rate limits.
- Масштаб: использовать Colly или распределённую очередь, хранить результаты в БД и следить за SLI/SLO (время отклика, успешные запросы).
Шаблон рабочей последовательности (мини-SOP)
- Описать цель сбора и поля для извлечения.
- Проанализировать структуру страницы в DevTools.
- Написать селекторы и локальные тесты на статическом HTML.
- Добавить обработку ошибок и повторные попытки.
- Настроить ограничения скорости и таймауты.
- Логировать метрики и ошибки, мониторить корректность данных.
Чеклист для разных ролей
Разработчик:
- Написал модуль запросов с таймаутом.
- Добавил парсер goquery и тесты на примерах HTML.
- Экспортировал поля для сериализации.
DevOps:
- Настроил очереди и ограничители запросов.
- Развернул мониторинг и алерты на падающий успех запросов.
Аналитик данных:
- Проверил качество извлечённых полей на примерах.
- Настроил трансформации и валидацию перед загрузкой в хранилище.
Частые ошибки и как их избежать
- Неправильные селекторы — решается инспекцией DOM и использованием более специфичных путей.
- Отсутствие обработки ошибок сети — добавьте повторные попытки и таймауты.
- Сохранение необработанных данных — всегда нормализуйте текст и проверяйте атрибуты.
Совместимость и миграция
- goquery работает с net/html; при переходе на более сложные JS-рендерящие страницы переходите на ChromeDP.
- При масштабировании переходите с локального хранилища на реляционную или NoSQL БД.
Примеры конфигураций и сниппеты
Настройка http.Client с таймаутом:
client := &http.Client{
Timeout: 10 * time.Second,
}
resp, err := client.Get(url)Пример тримминга текста:
raw := selector.Find("td.title").Text()
title := strings.TrimSpace(raw)Приватность и соответствие регуляциям
Если вы обрабатываете персональные данные, учитывайте требования GDPR и локальные законы. Храните минимально необходимый объём данных и документируйте основания обработки.
Итог и рекомендации
goquery — отличный старт для задач по вытягиванию данных со статичных страниц. Он прост, эффективен и легко интегрируется в приложения на Go. Для динамического контента и больших масштабов рассмотрите ChromeDP или Colly. Всегда начинайте с малого: протестируйте селекторы на статическом HTML, добавьте обработку ошибок и ограничения скорости, затем масштабируйте.
Заметка: документируйте источник данных и частоту обновления — это поможет отслеживать качество и соответствие закону.
Ключевые шаги по памяти: запрос → парсинг → селектор → сохранение. Следуйте чеклисту SOP перед запуском на продакшн.
Резюме
- goquery подходит для статичных сайтов и быстрого прототипирования.
- Для JS-рендеринга используйте ChromeDP или headless-браузер.
- Добавляйте таймауты, ретраи, rate-limiting и логирование.
- Соблюдайте юридические и этические требования при сборе данных.
В следующем проекте начните с простого скрипта на goquery и постепенно вносите улучшения по мере роста требований.
Похожие материалы
Как сменить язык в Tor Browser на ПК и Android
Отключить Windows Copilot в Windows 11
Включение Google Assistant: сделать Android похожим на Pixel
Dell SupportAssist OS Recovery — что это и как пользоваться
Удаление файлов и папок через CMD в Windows 10