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

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

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

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

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

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

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

Страница новости весит полтора мегабайта, а текста в ней — пятнадцать килобайт: всё остальное — картинки, шрифты, счётчики и стили, которые парсеру не нужны, но которые браузер честно качает, декодирует и держит в памяти. На сотнях страниц это часы времени и гигабайты трафика, а каждый лишний запрос — ещё и шанс словить перишаговый таймаут из пятнадцатого урока. Блокировка мусора — самый дешёвый способ ускорить обход: не оптимизировать код, а просто не качать то, что никогда не понадобится. В 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 — картинки не участвовали ни в загрузке, ни в извлечении, и страница отдала контент быстрее.

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

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

Флаг не умеет нюансов: он либо отключает картинки везде, либо нигде. Точность даёт перехват из семнадцатого урока: Fetch-домен останавливает браузер перед каждым запросом и даёт решить его судьбу. Включается перехват вызовом 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, — но проверка обязательна: сравните извлечённый текст с блокировкой и без на десятке страниц и зафиксируйте расхождения. Второй эффект — скриншоты из седьмого урока: снимок страницы без картинок — это серые заглушки, съехавший лейаут и места под изображения нулевой высоты; для визуальных задач блокировка запрещена полностью. Третий, более редкий: скрипты, которые ждут события onload у картинок или считают метрики по их размерам, — они виснут или делят на ноль. Общий принцип: блокировка меняет страницу, поэтому выборочные сверки текста — часть пайплайна, а не паранойя.

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

Измерение — это time.Since вокруг Run, как в первом примере: одна и та же очередь страниц, два аллокатора — с флагом и без — и два числа в конце. Сравнивайте не среднее, а распределение: медиану и хвост p95 — блокировка выигрывает именно на хвосте, отрезая медленные медиа-запросы, которые тянут страницу за собой. Связь с пятнадцатым уроком прямая: таймауты подбираются под распределение времени страницы, и после блокировки хвост укорачивается — перишаговый потолок можно снизить без роста доли ретраев, а общий дедлайн задания ужать, пропустив больше страниц за окно расписания. Вторая метрика — байты: счётчик из перехвата или внешний замер на интерфейсе. Третья — доля страниц, где извлечённый текст совпал с контрольным прогоном без блокировки: это индикатор сломанного 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") при старте аллокатора?

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

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

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

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

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

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

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

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

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

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

Строки

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

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

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

Термин

blink-settings=imagesEnabled=false

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

Флаг Blink-движка через chromedp.Flag: картинки не запрашиваются вообще. Действует на весь процесс браузера — все вкладки инстанса, отмена только пересозданием.

1 / 6

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

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

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

Вывод

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

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

  • Медиа-ресурсы съедают до 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 это или что-то ещё. Финал: снизьте перишаговый таймаут после блокировки и убедитесь, что доля ретраев не выросла.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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