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

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

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

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

Установка и первый запуск Chrome

chromedp установка удивительно короткая: один go get — и пакет в проекте, потому что кроме библиотеки не нужен ни драйвер, ни сервер, ни cgo. Всё остальное окружение — это Chrome на машине и пара строк каркаса: chromedp navigate делает первый переход уже в третьем уроке, а здесь соберём программу целиком и поймём, откуда берётся браузер и что происходит при первом запуске.

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

Новая задача: мониторить страницу конкурента и снимать скриншот каждый час. Идея понятна, но руки чешутся сразу от одного вопроса из прошлого опыта с Selenium: сколько всего придётся поставить и сшить между собой — драйвер, сервер, версии, зависимости? С chromedp этот вопрос снимается на первом шаге: библиотека сама запускает браузер, а единственное требование к машине — чтобы Chrome или Chromium был установлен. В этом уроке пройдём весь путь первого запуска: добавим пакет в модуль, найдём, где chromedp ищет браузер на Windows, macOS и Linux, соберём каркас программы с таймаутом и заглянем под капот первого Run — что именно происходит между go run и появлением процесса Chrome в системе. После этого урока любая программа курса будет выглядеть знакомо: одинаковое начало, одинаковая уборка за собой.

chromedp установка: go get и никакого chromedriver#

Проект собирается как обычный Go-модуль: папка, go mod init, добавление пакета. Никаких шагов вне Go-экосистемы не существует — это главная разница с браузерными инструментами из других языков, где к проекту прилагается бинарник драйвера, который должен совпадать по версии с браузером. В chromedp chromedriver не нужен в принципе: библиотека общается с Chrome по протоколу отладки, встроенному в сам браузер, а сам chromedp — чистый Go без cgo, поэтому кросс-компиляция не страдает. chromedp установка сводится к трём командам терминала, а версии пакета и его зависимостей фиксируются в go.mod и go.sum штатным механизмом модулей. Требования к окружению минимальные: установленный Chrome или Chromium — тот же, что стоит у вас на рабочей машине, и достаточно свежий Go. Для серверов есть путь аккуратнее: Docker-образ с предустановленным браузером, чтобы версии не гуляли между машинами, — ему посвящён отдельный урок про Docker и серверное окружение, а пока работаем локально.

Три команды до первой программы

GO
mkdir chromedp-hello && cd chromedp-hello
go mod init example.com/chromedp-hello
go get github.com/chromedp/chromedp

go run .

go mod init создаёт модуль, go get добавляет chromedp в зависимости и фиксирует версию в go.mod и go.sum. Последняя строка запускает программу из текущей папки. Отдельного шага установки драйвера нет: пакет скомпилируется сам, а браузер будет найден при первом запуске.

Первый ctx: NewContext, ленивый запуск и defer cancel#

Сердце программы — две функции, и важно понимать разницу между ними. chromedp.NewContext(context.Background()) только готовит контекст: он запоминает настройки сессии, но не запускает ни одного процесса. Проверить это легко — поставьте после NewContext вызов os.Exit и убедитесь, что в системе не появилось ни одного процесса браузера. Ленивость здесь осмысленная: пока нет действий, браузер не нужен. Процесс стартует на первом chromedp.Run — это самый дорогой вызов программы, на него уходят и старт браузера, и подключение к нему. Отсюда практическое правило: NewContext и Run разделяют Initialization и работу, а между ними удобно навешивать таймауты. Вторая функция — cancel из пары: отмена первого контекста закрывает весь браузер, поэтому defer cancel() в main — обязательная гигиена каждого примера курса. Забытый cancel не приведёт к ошибке компиляции, но оставит висеть процесс Chrome — на ноутбуке это заметно по вентилятору, а на сервере — по памяти, которая кончилась в три часа ночи. Ещё одна деталь того же семейства: контекст можно готовить заранее, и это дёшево — программа создаёт сессии про запас и запускает их по мере необходимости, потому что цена NewContext — записать настройки, а не запустить процесс. Ленивость тут не экономия ради экономии: старт браузера — самое хрупкое место программы, и группировать его в одном месте — значит видеть все точки, где он может не удастся.

Откуда chromedp берёт Chrome: путь по умолчанию#

При старте библиотека ищет браузер по списку стандартных мест, и список этот зависит от операционной системы. На macOS проверяются приложения Chromium и Google Chrome в папке Applications. На Windows — путь через PATH и папки Program Files, включая профиль пользователя в AppData. На Linux список длиннее всего: chromium, chromium-browser, google-chrome, google-chrome-stable и его бета-варианты, /usr/bin/google-chrome, /usr/local/bin/chrome, а также /snap/bin/chromium — на Ubuntu браузер часто живёт именно в snap. Первый найденный бинарник и станет рабочим. Отсюда частая путаница на Linux: у вас стоит chromium, программа ищет google-chrome — и находит, потому что поиск идёт по всему списку, а не по одному имени. Если браузер лежит в нестандартном месте — кастомная сборка, отдельная версия для тестов, — путь передают явно опцией ExecPath при создании allocator-контекста, о котором ниже. Когда поиск ни к чему не привёл, chromedp не молчит: он возвращает ошибку запуска с именем, которое не нашлось, — и это обычно первый сигнал проверить, установлен ли браузер вообще. Список путей не секретная величина, а задокументированное поведение: на него можно опираться в скриптах развёртывания, зная, где именно следует ожидать бинарник.

Нестандартный путь и видимое окно: allocator-контекст

GO
options := append(chromedp.DefaultExecAllocatorOptions[:],
        chromedp.Flag("headless", false),        // показать окно браузера
        chromedp.ExecPath("/usr/bin/chromium"),  // свой путь к бинарнику
)

allocCtx, cancel := chromedp.NewExecAllocator(context.Background(), options...)
defer cancel()

ctx, cancel := chromedp.NewContext(allocCtx)
defer cancel()

DefaultExecAllocatorOptions — набор флагов по умолчанию, где уже включён headless; мы дописываем своё поверх него. Flag передаёт Chrome любые флаги командной строки, а ExecPath задаёт путь к бинарнику, если он не в стандартном месте. NewExecAllocator создаёт контекст запуска браузера, а NewContext на его основе — рабочую сессию; обе пары cancel нужно закрыть.

Headless по умолчанию и что меняет окно#

chromedp стартует Chrome с набором флагов по умолчанию, и главный среди них — headless: окно не рисуется, интерфейс не существует, но движок полностью рабочий. К этому режиму добавлены тишина звука и скрытые полосы прокрутки — детали, которые не мешают автоматизации. Для повседневных задач headless — правильный режим: быстрее старт, меньше памяти, работает на сервере без дисплея. Но при отладке он прячет самое ценное — собственно страницу. Половина вопросов новичков — «почему селектор не находится» — решается за минуту, когда запускаешь программу с видимым окном и смотришь, что реально открылось: редирект на капчу, баннер согласия с куками, мобильная версия. Включается окно одной опцией Flag(«headless», false) из блока выше — базовый набор флагов при этом сохраняется. Отдельный практический нюанс: даже в headless у страницы есть размеры окна, и от них зависит вёрстка, которая отрисуется. Размер задают опцией WindowSize — это заметно на сайтах с адаптивом, где от ширины вьюпорта меняется вся сетка. Последний штрих к режимам: окно — не только отладка, но и редкие задачи со свойствами, привязанными к отображению, вроде печати страницы в PDF с точными полями; но в повседневной работе headless возвращается сразу, как только причина отладки устранена.

Что происходит при первом Run#

Первый Run — самое насыщенное место всей программы, и полезно знать его этапы. Сначала chromedp собирает аргументы командной строки из опций allocator: headless, отключённые первые-запуски, порт отладки со случайным номером — если порт не задан явно, — и готовит временный каталог профиля: по умолчанию свежая папка в системном tmp, чтобы сессии не мешали друг другу и не тащили историю; каталог сразу уезжает в браузер опцией user-data-dir. Затем стартует процесс Chrome с пустой первой страницей, и библиотека читает его вывод, пока там не появится строка с адресом отладки — на неё вешается WebSocket-подключение; если браузер молчит слишком долго, Run завершается ошибкой таймаута чтения адреса. После подключения создаётся вкладка — target, — и только теперь исполняются ваши действия. Всё это занимает доли секунды на быстрой машине, но на слабом CI растягивается заметно, поэтому первый Run и любят оборачивать запасным таймаутом. Здесь же живут две типовые ошибки. Первая — запуск как root в Linux-контейнере без песочницы Chrome: chromedp сам добавит нужный флаг, но понимать механику стоит. Вторая — context canceled посреди работы: соединение с браузером оборвалось, процесс убит или закрыт вручную, и chromedp отменил контекст, чтобы не врать про успех. Правильная реакция на неё — не глушить, а логировать и решать: ретрай с новым контекстом или сигнал о проблеме окружения. Знание этих этапов экономит часы: когда программа зависает, по месту затыка сразу видно, что сломалось — старт процесса, подключение или уже сами действия.

Настройка запуска браузера#

ЗадачаИнструментКомментарий
Запуск по умолчаниюchromedp.NewContext(context.Background())headless включён, путь к Chrome ищется по стандартным местам
Свой путь к бинарникуchromedp.ExecPath(path) в NewExecAllocatorкастомная сборка, отдельная версия, нестандартный путь
Видимое окно при отладкеchromedp.Flag("headless", false)дописывается к DefaultExecAllocatorOptions
Профиль и данныеопция UserDataDirбез неё — свежий временный каталог на каждую сессию
Сервер без настройкиготовый образ с браузеромотдельный урок про Docker закрывает версии и зависимости

Чек-лист первого запуска#

  • модуль создан, chromedp добавлен через go get, версия зафиксирована в go.mod
  • браузер отвечает на google-chrome --version или chromium --version в терминале
  • в main есть defer cancel() сразу после NewContext
  • на прогон навешен таймаут через context.WithTimeout
  • ошибка Run обрабатывается, а не глотается — по ней видно, что именно сломалось
  • при отладке включено видимое окно или WithDebugf для лога протокола

Проверка: момент запуска

В какой момент chromedp запускает процесс Chrome?

Проверка: браузер не найден

Run вернул ошибку запуска — Chrome не нашёлся. Какой способ починки рабочий?

Где вылезет ошибка

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

// Сервер без браузера. Как упадёт программа?
// ctx, cancel := chromedp.NewContext(context.Background())
// defer cancel()
// time.Sleep(time.Second)
// err := chromedp.Run(ctx, chromedp.Navigate("https://example.com"))

Соберите allocator с видимым окном

Восстановите настройку запуска: флаг Chrome, создание allocator-контекста и рабочей сессии.

options := append(chromedp.DefaultExecAllocatorOptions[:], chromedp.("headless", false), ) allocCtx, cancel := chromedp.(context.Background(), options...) defer cancel() ctx, cancel := chromedp.(allocCtx) defer cancel()

Расставьте настройку запуска

Соберите по порядку программу с кастомными опциями: от среза опций до первого действия.

Строки

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

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

Карточки: установка и запуск

Термин

go get github.com/chromedp/chromedp

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

Вся установка библиотеки. Драйверов и серверов нет: нужен только установленный Chrome или Chromium и обычный Go-модуль.

1 / 6

Что дальше: программа умеет запускаться, но пока просто открывает страницу. Первый настоящий chromedp navigate случится уже в третьем уроке — навигация и ожидание загрузки покажут, что Navigate возвращает управление раньше, чем на странице появляются данные, и научат ждать честно. Фундамент каркаса — контексты и таймауты — это чистая стандартная библиотека, и если хочется освежить её до того, как примеры станут сложнее, загляните в основы Go. А карта всех двадцати пяти тем живёт на странице курса. Напоминание про песочницу: этот урок — про терминал и процессы, поэтому запускать его нужно локально; интерактивы выше проверяют понимание механики, а не исполняют chromedp.

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

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

Вывод

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

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

  • Установка chromedp — один go get: чистый Go без cgo, драйверов и серверов; нужна только библиотека и установленный Chrome.
  • NewContext готовит контекст, но не запускает процессов — браузер стартует на первом Run, и ошибки окружения вылезают именно там.
  • Путь к Chrome ищется по стандартным местам ОС; нестандартный бинарник передают через ExecPath в allocator-контексте.
  • Headless включён по умолчанию; Flag("headless", false) показывает окно — главный приём отладки «почему селектор не находит».
  • Первый Run стартует процесс, создаёт временный профиль, подключается по WebSocket и открывает вкладку — самый дорогой вызов программы.
  • defer cancel() обязателен: отмена первого контекста закрывает браузер, забытый cancel оставляет процессы висеть.
  • context canceled после обрыва с браузером — штатный сигнал, что сессия умерла, а не повод глушить ошибку.
  • WithDebugf выводит обмен протокола в лог — быстрый способ увидеть, на каком этапе зависла программа.

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

Соберите проект из урока: модуль, go get, main с каркасом из первого запуска и переходом на example.com. Затем умышленно сломайте окружение — задайте ExecPath на несуществующий путь — и убедитесь, что ошибку вернёт Run, а не NewContext. После этого верните путь и включите видимое окно через Flag("headless", false): посмотрите на страницу глазами браузера и запишите, чем вкладка Elements отличается от исходного кода.

Личные заметкиПусто
Хранятся только в вашем браузере (Chromedp · Установка и первый запуск Chrome)

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

Нужен ли именно Chrome или подойдёт Chromium?

Подойдёт любой браузер на движке Chromium, который умеет протокол отладки: Google Chrome, Chromium, headless-shell. chromedp ищет их по стандартным путям; Edge и Brave тоже работают, но путь к ним задают явно через ExecPath.

Нужно ли ставить Chrome сам по себе?

Да — это единственное требование chromedp к системе, и библиотека ничего не скачивает сама. На сервере браузер ставят вместе с приложением или берут готовый Docker-образ; отдельный урок курса разбирает образ с предустановленным Chrome и шрифтами. Версии библиотеки и браузера не сшиты жёстко: протокол отладки развивается совместимо, поэтому свежий Chrome со «старым» chromedp обычно работает. Но крайние комбинации иногда ломают отдельные команды — ещё один аргумент фиксировать образ с браузером на сервере, а не обновлять его вслепую.

Почему ошибка запуска браузера вылезает не сразу?

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

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

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

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

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

Testcontainers в Go: интеграционные тесты с Docker

Курс testcontainers-go: Postgres, Redis, Kafka и Mongo в тестах через Docker, wait-стратегии, сети, параллельность, CI и итоговый стенд. 25 уроков.

  • Поднимать реальные зависимости в Docker из кода теста
  • Использовать модули Postgres, Redis, MongoDB, Kafka и RabbitMQ
  • Ждать готовность сервиса wait-стратегиями вместо sleep
  • Собирать стенды из нескольких контейнеров и своего образа