---
title: "Блокировка картинок и шрифтов"
description: "chromedp блокировка изображений и шрифтов: флаг Chrome, Fetch-перехват и CSS. Флаги экономии: скрапинг без мусора и быстрее. Меньше трафика — меньше ретраев."
course: "Chromedp в Go: автоматизация Chrome без Selenium"
url: "https://golangmaster.ru/courses/chromedp/lessons/18-blokirovka-resursov/"
published: "2026-09-19"
updated: "2026-09-21"
minutes: 16
---

# Блокировка картинок и шрифтов

*Курс «Chromedp в Go: автоматизация Chrome без Selenium», урок 18 из 25. ~16 минут. Обновлено 21.09.2026. Источник: https://golangmaster.ru/courses/chromedp/lessons/18-blokirovka-resursov/*

chromedp блокировка изображений — первый приём экономии, который стоит включать почти в каждом парсере: страница статьи весит полтора мегабайта, а текста в ней пятнадцать килобайт, и всё остальное браузер качает зря. Экономия трафика здесь неотделима от экономии времени: меньше запросов — короче загрузка — ниже риск упереться в таймауты из пятнадцатого урока. Разберём три уровня отключения мусора — флаг Chrome на весь процесс, адресный перехват Fetch и CSS-подмену, — а заодно честно посмотрим, что при этом ломается и как измерить выигрыш числами, а не ощущениями.

Страница новости весит полтора мегабайта, а текста в ней — пятнадцать килобайт: всё остальное — картинки, шрифты, счётчики и стили, которые парсеру не нужны, но которые браузер честно качает, декодирует и держит в памяти. На сотнях страниц это часы времени и гигабайты трафика, а каждый лишний запрос — ещё и шанс словить перишаговый таймаут из пятнадцатого урока. Блокировка мусора — самый дешёвый способ ускорить обход: не оптимизировать код, а просто не качать то, что никогда не понадобится. В chromedp это делается на трёх уровнях, и у каждого своя цена. Флаг на процесс груб, но бесплатен: одна строка при старте. Перехват запросов гибок: правила по типу и адресу, но это ручной код. CSS-подмена — паллиатив, который убирает шрифты и фоны, но не трогает теги img. Выигрыш зависит от сайта: на лёгких текстовых страницах он скромный, на медиа-тяжёлых — кратный, поэтому ниже не только приёмы, но и способ измерить их на вашей цели, а не в чужих статьях. Ниже — все три уровня, таблица «ресурс против цены отключения», разбор поломок и измерение: как убедиться, что выигрыш реален, а не выдуман.

### Зачем отключать картинки и шрифты

Экономия трафика начинается с аудита: откройте вкладку Network на типичной странице цели и посмотрите, сколько весят типы image и font против document. Типовая раскладка медиа-тяжёлой страницы — до 80% байтов уходит на картинки и шрифты, и это байты, которые текстовому парсеру не достанутся никогда. Помимо трафика каждый ресурс стоит соединения: TLS-рукопожатие, очередь, декодирование, память под распакованный битмап; шрифты вдобавок задерживают отрисовку текста, пока не подгрузятся сами. Для извлечения данных через chromedp.Text всё это чистый убыток: страница платит за то, что не читается. Обратная сторона: картинки и шрифты жизненно нужны, когда вы снимаете скриншоты, верстаете PDF или проверяете, что страница выглядит как положено, — там отключение сломает задачу, и граница видна в таблице ниже. Правило простое: сначала тип задачи, потом уровень блокировки. Текстовому обходу — агрессивный флаг на весь инстанс, скриншотному сервису — точечный перехват или ничего, потому что серый скриншот без картинок никому не сдался.

### Флаг imagesEnabled и замер времени загрузки

```go
opts := append(chromedp.DefaultExecAllocatorOptions[:],
        chromedp.Flag("blink-settings", "imagesEnabled=false"),
)
allocCtx, allocCancel := chromedp.NewExecAllocator(context.Background(), opts...)
defer allocCancel()

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

start := time.Now()
var text string
err := chromedp.Run(ctx,
        chromedp.Navigate(url),
        chromedp.WaitVisible("article"),
        chromedp.Text("article", &text),
)
log.Printf("готово за %s, %d символов, err=%v",
        time.Since(start), len(text), err)
```

Flag — универсальная опция аллокатора: строковое значение уезжает в командную строку Chrome как --blink-settings=imagesEnabled=false. Замер строится на time.Since вокруг Run: Navigate плюс WaitVisible дают полное время до готовности статьи. Текст приходит через chromedp.Text — картинки не участвовали ни в загрузке, ни в извлечении, и страница отдала контент быстрее.

### Флаг Chrome: blink-settings на весь процесс

chromedp блокировка изображений самым грубым способом — это флаг: chromedp.Flag("blink-settings", "imagesEnabled=false"). Из исходников библиотеки видно, что Flag принимает имя и значение любого типа: строка уезжает в командную строку как --name=value, булево — как голый --name; Blink — движок рендеринга, и эта настройка запрещает ему запрашивать картинки вовсе: вёрстка живёт, на месте картинок пусто, трафика ноль. Ключевое свойство — область действия: флаг ставится на аллокатор, то есть на весь процесс браузера, и все вкладки этого инстанса будут без картинок; выключить для одной вкладки нельзя. Отсюда дизайн: если в программе соседствуют текстовый парсер и скриншотчик, заводите два аллокатора с разными флагами — инстанс в chromedp дёшев, это отдельный процесс с собственными настройками. Флаги читаются один раз при старте процесса: поменять на лету нельзя, только пересоздать браузер — за гибкость на живом браузере отвечает перехват из следующего раздела.

> **Живое место: скриншоты, которые стали серыми.** Дежурный сервис снимал скриншоты витрин для отчётов, и кто-то «для скорости» добавил imagesEnabled=false в общий аллокатор — тот, из которого брали контексты все задачи подряд. Текстовые задания правда ускорились, а скриншоты превратились в белые листы с подписями: картинки не скачались, лейаут сжался, товарные карточки схлопнулись в полоски. Поиск занял день, потому что флаг сработал не там, где его читали: виноват оказался общий аллокатор, а не скриншотный код. Лечение — два аллокатора: блокирующий для текста и чистый для визуала, и правило «флаг на процесс, а не на программу». Спорное мнение с условием: один общий флаг допустим, если скриншотные задачи ходят в отдельный браузер по дизайну, а не по привычке — иначе рано или поздно кто-то их смешает.

### Перехват Fetch: блокировка по URL и типу

Флаг не умеет нюансов: он либо отключает картинки везде, либо нигде. Точность даёт перехват из семнадцатого урока: [Fetch-домен](/courses/chromedp/lessons/17-perehvat-zaprosov/) останавливает браузер перед каждым запросом и даёт решить его судьбу. Включается перехват вызовом fetch.Enable с паттернами: RequestPattern описывает, какие запросы ставить на паузу, — поля URLPattern и ResourceType; паттерны на image и font ловят ровно мусор и не трогают документы и скрипты. Каждый пойманный запрос приходит событием EventRequestPaused, и ответов два: ContinueRequest пропустить дальше или FailRequest с причиной ErrorReasonBlockedByClient — браузер увидит обычный сетевой отказ, страница отработает его как недоступный ресурс. Здесь доступен и адрес: чёрный список трекеров, белый список для CDN картинок нужного домена, правило «блокировать всё тяжёлое с чужих хостов». Плата за гибкость — код: обработчик событий, горутина на каждое событие и аккуратность с контекстом.

### Fetch-блокировщик картинок и шрифтов

```go
import (
        "github.com/chromedp/cdproto/fetch"
        "github.com/chromedp/cdproto/network"
)

// обработчик ставится до Navigate
chromedp.ListenTarget(ctx, func(ev interface{}) {
        paused, ok := ev.(*fetch.EventRequestPaused)
        if !ok {
                return
        }
        go func() {
                if err := fetch.FailRequest(paused.RequestID,
                        network.ErrorReasonBlockedByClient).Do(ctx); err != nil {
                        log.Printf("блок: %v", err)
                }
        }()
})

err := chromedp.Run(ctx,
        fetch.Enable().WithPatterns([]*fetch.RequestPattern{
                {URLPattern: "*", ResourceType: network.ResourceTypeImage},
                {URLPattern: "*", ResourceType: network.ResourceTypeFont},
        }),
        chromedp.Navigate(url),
)
```

С ListenTarget из шестнадцатого урока обработчик ловит паузы. Паттерны с ResourceType сужают перехват: на паузу встают только картинки и шрифты, остальное браузер не трогает вовсе. Каждому событию отвечает FailRequest с причиной BlockedByClient — страница видит сетевой отказ. Горутина на событие обязательна: обработчик не должен тормозить поток событий.

### Ресурс → можно ли отключить → чем платим

| Ресурс | Можно ли отключить | Чем платим |
| --- | --- | --- |
| Картинки | да: флаг blink-settings или Fetch-паттерн | серые скриншоты, возможен сломанный lazy-loading |
| Шрифты | да: Fetch-паттерн или CSS-подмена | меняется ширина букв — ломаются координаты кликов |
| Фоновые CSS-картинки | да: CSS background-image: none | почти ничего: фон на извлечение текста не влияет |
| Стили | осторожно: только точечно | без CSS скрытые элементы не кликнутся, лейаут плывёт |
| Скрипты | обычно нет | SPA перестанет рендерить данные — уйдёт и контент |
| Аналитика и трекеры | да: Fetch по URL-чёрному списку | практически ничего: меньше шума и трафика |

Третий способ — самый мягкий: не запрещать загрузку, а убедить страницу не запрашивать лишнее. Шрифты отпадают сами, если переопределить font-family на системные: браузер качает веб-шрифт только когда элемент реально им оформлен, и подмена семейства одним style-тегом отменяет загрузку всех @font-face целиком. Картинки так не убрать: атрибут src в HTML загружается независимо от CSS, а display:none лишь прячет уже скачанное, — поэтому CSS-приём про шрифты, фоны и хвосты: background-image: none вырубает фоновые картинки, а вот тегу img он не указ. Внедряется подмена через Evaluate из десятого урока: одна строка кода создаёт style-тег с нужными правилами. Достоинство метода — точечность: применить можно к одной вкладке, не трогая соседние, и без перезапуска браузера; недостаток честный — это договорённость с вёрсткой, а не запрет на уровне сети, и страницы со своими стилями могут переиграть подмену специфичностью селекторов. Отдельный бонус: без веб-шрифтов почти исчезает сдвиг раскладки в момент загрузки, и WaitVisible на текстовые элементы срабатывает стабильнее.

### Что ломается: lazy-loading и скриншоты

Отключённые ресурсы меняют поведение страницы, и два эффекта надо знать заранее. Первый — lazy-loading: у сайтов с ленивыми картинками контент часто появляется по IntersectionObserver, когда картинка вот-вот войдёт в экран; с imagesEnabled=false картинки «не существуют», триггер молчит, и часть текста может не отрендериться вовсе. Для скрапинга это обычно не больно — основной контент лежит в HTML, — но проверка обязательна: сравните извлечённый текст с блокировкой и без на десятке страниц и зафиксируйте расхождения. Второй эффект — скриншоты из седьмого урока: [снимок страницы](/courses/chromedp/lessons/07-skrisnty/) без картинок — это серые заглушки, съехавший лейаут и места под изображения нулевой высоты; для визуальных задач блокировка запрещена полностью. Третий, более редкий: скрипты, которые ждут события onload у картинок или считают метрики по их размерам, — они виснут или делят на ноль. Общий принцип: блокировка меняет страницу, поэтому выборочные сверки текста — часть пайплайна, а не паранойя.

> **Про песочницу: где честно мерить.** В песочнице этого сайта эффект не показать: она исполняет тематическую программу на чистом Go без браузера, и никакого сетевого трафика картинок там нет. Замер делается локально: возьмите десять-двадцать адресов цели, прогоните с флагом и без на одном железе и сравните медиану, а не лучший прогон — тёплая сеть и кэш DNS умеют врать. Заодно сложите байты: сколько трафика съели картинки в контрольном прогоне. Локальный запуск на медленном канале покажет выигрыш ярче всего — блокировка там ускоряет обход в разы, а не на проценты.

### Измерение эффекта и связь с таймаутами

Измерение — это time.Since вокруг Run, как в первом примере: одна и та же очередь страниц, два аллокатора — с флагом и без — и два числа в конце. Сравнивайте не среднее, а распределение: медиану и хвост p95 — блокировка выигрывает именно на хвосте, отрезая медленные медиа-запросы, которые тянут страницу за собой. Связь с пятнадцатым уроком прямая: [таймауты](/courses/chromedp/lessons/15-tajmauty-i-prochnost/) подбираются под распределение времени страницы, и после блокировки хвост укорачивается — перишаговый потолок можно снизить без роста доли ретраев, а общий дедлайн задания ужать, пропустив больше страниц за окно расписания. Вторая метрика — байты: счётчик из перехвата или внешний замер на интерфейсе. Третья — доля страниц, где извлечённый текст совпал с контрольным прогоном без блокировки: это индикатор сломанного lazy-loading, и растущий процент здесь — сигнал вернуть ресурсы хотя бы выборочно, через Fetch-паттерн для нужного домена.

### Чек-лист блокировки ресурсов

- аудит Network перед блокировкой: сколько реально весят image и font на вашей цели
- текстовый обход — флаг imagesEnabled=false на весь инстанс: дёшево и грубо
- выборочная блокировка — Fetch-паттерны по ResourceType и URL из семнадцатого урока
- шрифты добиваются CSS-подменой font-family; тег img CSS не отменяет
- скриншоты и PDF — без блокировки: им отдельный аллокатор без флага
- lazy-loading проверяется сверкой текста с блокировкой и без
- медиана и p95 вместо среднего: блокировка выигрывает на хвосте распределения

### Проверка: флаг blink-settings

**Вопрос:** Что сделает chromedp.Flag("blink-settings", "imagesEnabled=false") при старте аллокатора?

- ✅ Допишет Chrome флаг --blink-settings=imagesEnabled=false: картинки не будут запрашиваться во всех вкладках этого инстанса
- Отключит картинки только в той вкладке, которая создана от этого контекста
- Заблокирует только картинки с чужих доменов, свои останутся
- Ничего не сделает: настройки blink-settings в Chrome не существует

Flag — универсальная опция аллокатора: строковое значение уходит в командную строку процесса Chrome как --name=value. Blink перестаёт запрашивать картинки, и действует это на весь процесс: все вкладки инстанса делят один набор флагов, выключить его для отдельной вкладки нельзя. На лету флаги тоже не меняются — только пересоздание браузера.

### Проверка: раскладка по аллокаторам

**Вопрос:** В программе текстовый парсер и скриншотный сервис. Как разложить блокировку по аллокаторам?

- Один аллокатор с флагом: скриншотам картинки не нужны, они снимают текст
- ✅ Два аллокатора: блокирующий для текста, чистый для скриншотов
- Флаг ставится на вкладку через NewContext, аллокаторы не важны
- Блокировка включается и выключается на живом браузере по флагу задачи

Флаг действует на весь процесс, а скриншотам картинки необходимы — без них снимок серый и съехавший. Поэтому два аллокатора: у каждого свой процесс и свой набор флагов. На вкладке блокировку флагом не включить, а на живом браузере флаги не меняются: гибкое переключение — это Fetch-перехват, но для постоянных режимов чище держать два инстанса.

### Что попадёт под перехват

```go
fetch.Enable().WithPatterns([]*fetch.RequestPattern{
        {URLPattern: "*", ResourceType: network.ResourceTypeImage},
        {URLPattern: "*", ResourceType: network.ResourceTypeFont},
})
// обработчик шлёт FailRequest каждому пойманному запросу
// затем Run: Navigate(url) на страницу со скриптами и стилями
```

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

- ✅ Скрипты и стили выполнятся как обычно: под паттерны они не попадают и на паузу не встают
- Всё остановится: URLPattern * ловит каждый запрос страницы
- Страница не откроется: навигация заблокируется первым же паттерном
- Скрипты выполнятся, а стили заблокируются как шрифты

Паттерны с ResourceType описывают, какие запросы ставить на паузу: здесь это только image и font. Документ, скрипты и стили под перехват не попадают и грузятся без участия обработчика, поэтому страница работает как обычно, минус заблокированные ресурсы. Навигация — это document, и она тоже не остановлена: страница откроется.

### Соберите блокирующий аллокатор

Восстановите опции и создание аллокатора с флагом отключения картинок.

```go
opts := append(chromedp.DefaultExecAllocatorOptions[:],
        chromedp.___("blink-settings", "___=false"),
)
allocCtx, allocCancel := chromedp.___(context.Background(), opts...)
defer allocCancel()
```

Подсказка: Универсальный флаг ставит chromedp.Flag, настройка называется imagesEnabled, а аллокатор создаёт NewExecAllocator.

Правильные ответы в пропусках: `Flag`, `imagesEnabled`, `NewExecAllocator`

### Расставьте каркас блокирующего обхода

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

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

1. `opts := append(chromedp.DefaultExecAllocatorOptions[:],`
2. `  chromedp.Flag("blink-settings", "imagesEnabled=false"),`
3. `)`
4. `allocCtx, allocCancel := chromedp.NewExecAllocator(context.Background(), opts...)`
5. `defer allocCancel()`
6. `ctx, cancel := chromedp.NewContext(allocCtx)`
7. `defer cancel()`
8. `err := chromedp.Run(ctx, chromedp.Navigate(url), chromedp.WaitVisible("main"))`
9. `log.Printf("%s: %s", url, time.Since(start))`

### Карточки: блокировка ресурсов

- **blink-settings=imagesEnabled=false** — Флаг Blink-движка через chromedp.Flag: картинки не запрашиваются вообще. Действует на весь процесс браузера — все вкладки инстанса, отмена только пересозданием.
- **fetch.Enable + RequestPattern** — Перехват с паттернами: URLPattern задаёт маску адреса, ResourceType — тип (image, font). Под паттерн попал — событие EventRequestPaused, не попал — грузится без паузы.
- **FailRequest + ErrorReasonBlockedByClient** — Ответ перехватчика: браузер видит обычный сетевой отказ «заблокировано клиентом». Пара к ContinueRequest, который пропускает запрос дальше.
- **CSS-подмена шрифтов** — font-family на системные в style-теге через Evaluate: веб-шрифты не матчатся — не скачиваются. Фоны убирает background-image: none, но тегу img CSS не указ.
- **Lazy-loading при блокировке** — IntersectionObserver не видит картинок — триггер молчит, часть контента может не отрендериться. Для текста часто не страшно; проверяется сверкой с прогоном без блокировки.
- **Что измерять после блокировки** — Медиану и p95 времени загрузки, байты трафика и долю страниц с совпавшим текстом. Хвост укорачивается — перишаговые таймауты можно снижать без роста ретраев.

Что дальше: экономия — тактический приём, масштаб — стратегический, и они усиливают друг друга. Девятнадцатый урок соберёт [пул браузеров](/courses/chromedp/lessons/19-parallelnyj-pul/): воркеры над каналом задач, лимиты вкладок и несколько инстансов Chrome — там блокированный флагом инстанс становится дешёвой единицей масштаба, ведь сэкономленные мегабайты умножаются на число воркеров. Перед пулом полезно перечитать и пятнадцатый урок: дедлайны шагов в параллели работают точно так же, только страниц в минуту больше. Практика — локально: нужны установленные Go и Chrome, песочница сайта программы без браузера не исполняет, поэтому честный замер трафика и времени делается только на настоящем интернете — та же оговорка, что с таймаутами. Домашняя проверка: прогоните двадцать страниц цели с флагом и без, сравните медиану и p95, посчитайте сэкономленные байты и найдите страницу, где lazy-loading без картинок недоложил текст, — опознать её вы теперь умеете.

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

- Медиа-ресурсы съедают до 80% трафика страницы, а текстовому парсеру не нужны: блокировка — самый дешёвый разгон обхода.
- chromedp.Flag — универсальная опция аллокатора: строка уезжает в Chrome как --name=value и действует на весь процесс.
- imagesEnabled=false отключает картинки во всех вкладках инстанса; для одной вкладки это сделать нельзя.
- Точность даёт Fetch-перехват: паттерны по ResourceType image и font, решение по запросу — ContinueRequest или FailRequest.
- CSS-подмена отменяет загрузку шрифтов и фонов, но не отменяет src у тега img.
- Lazy-loading при блокировке может недоложить текст: сверяйте содержимое с контрольным прогоном.
- Скриншотам и PDF картинки нужны: им — отдельный аллокатор без блокирующих флагов.
- Измеряйте медиану, p95 и байты: блокировка выигрывает на хвосте распределения времени страницы.
- Укороченный хвост позволяет ужать перишаговые таймауты без роста доли ретраев.

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

Соберите два аллокатора — с флагом imagesEnabled=false и без — и прогоните по двадцать страниц цели в каждом, замеряя time.Since для каждой страницы. Посчитайте медиану, p95 и суммарные байты. Затем добавьте на второй аллокатор Fetch-блокировку по паттернам image и font и сравните с флагом: скорость, гибкость, объём кода. Найдите страницу, где текст с блокировкой отличается от текста без, — разберите, lazy-loading это или что-то ещё. Финал: снизьте перишаговый таймаут после блокировки и убедитесь, что доля ретраев не выросла.

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

### Флаг отключил картинки, а страница всё равно медленная. Что ещё качается?

Посмотрите в перехвате, что осталось: обычно это шрифты, тяжёлые стили, аналитика и видео. Шрифты добиваются CSS-подменой или Fetch-паттерном на font, трекеры — URL-чёрным списком, видео — паттерном на media. Замер по категориям из вкладки Network покажет следующего кандидата: гасите типы по одному и следите за медианой, чтобы поймать вклад каждого в общее время загрузки.

### Можно ли включать и выключать блокировку на живом браузере?

Флаги читаются при старте процесса и на лету не меняются — только новый инстанс с другим набором опций. На живом браузере управлять можно перехватом: fetch.Enable и Disable включаются на вкладке, а URL-правила обработчика читаются из конфига на каждое событие — их можно менять без перезапуска. Поэтому системы с разными режимами закладывают либо два аллокатора, либо перехват с конфигом.

### Блокирую картинки, но WaitVisible на карточку не срабатывает. Почему?

Скорее всего, карточка появляется по скрипту, который ждёт загрузки или размеров картинки, а с imagesEnabled=false картинка не запрашивается и триггер молчит. Сверьте текст контрольным прогоном без блокировки: если контент там есть, ищите селектор на элемент, не зависящий от картинки, или ждите через Poll по тексту. В крайнем случае верните картинки выборочно — Fetch-паттерном только для домена с нужными изображениями.
