Назад в Центр знаний
Начало работы

Сбор данных с Puppeteer: настройки и наблюдения

Области действия настроек запуска, viewport, хранения и headless в Puppeteer: наблюдения на собственном каталоге и проверка данных.

BotBrowser Team

Сбор данных с Puppeteer: настройки и наблюдения
Документация

Нужна структурированная документация по теме Начало работы?

Эта статья относится к редакционной библиотеке. Для пошаговой настройки, справки и постоянных обновлений переходите сразу в соответствующий раздел docs.

BotBrowser документирует запуск Puppeteer с профилем через puppeteer-core, executablePath, defaultViewport и --bot-profile; ответ стороннего сайта или результат детектора не гарантируется.

Кратко

Настройки сбора данных с Puppeteer действуют на разных уровнях. executablePath, headless и userDataDir относятся к процессу; defaultViewport задаёт эмуляцию страницы; BrowserContext управляет изолированным хранилищем браузера внутри процесса. Страница читает размеры или navigator.webdriver, но это не вердикт, не подтверждение личности и не разрешение доступа.

Используйте собственный каталог, фиксируйте бинарный файл и профиль, меняйте одну настройку и сохраняйте конечный URL, размеры, navigator.webdriver, число принятых записей и диагностику. Такое сравнение позволяет опровергнуть гипотезу, но не доказывает большую приемлемость режима или защиту приватности.

Содержание

Настройки процесса

Интеграция запуска Puppeteer описывает установку пакета и начальное подключение с профилем; сравнение ниже предполагает, что интеграция уже настроена.

executablePath выбирает исполняемый файл. Существование пути не подтверждает загрузку нужной сборки, принятие профиля или ответ сайта. Сохраняйте путь, версию пакета, версию исполняемого файла и аргументы, чтобы обнаружить изменение входных параметров процесса.

У headless три документированных значения: true использует текущий безголовый режим Chrome, 'shell' запускает отдельный chrome-headless-shell, false открывает браузер с интерфейсом. Поведение процесса, отрисовка и возможности интерфейса могут различаться. Это режимы выполнения, а не уровни доверия, принятия или права доступа. Страница выдаёт значения, а не решение сервера.

userDataDir задаёт каталог постоянных данных процесса. Это не файл профиля BotBrowser .enc и не BrowserContext. Параллельным процессам нужны разные каталоги для записи. Повторное использование может сохранить cookies и локальное хранилище, но одновременно связывает состояния запусков; указывайте это явно.

Настройка Puppeteer в BotBrowser документирует puppeteer-core, режим Chrome, executablePath, defaultViewport: null и --bot-profile. Справочник профилей описывает значения конфигурации. Ни один документ не обещает сторонний вердикт или ответ целевого сайта.

Области действия настроек Puppeteer: запуск процесса, страница и запись JSON

Страница и контекст

Через настройки страницы Puppeteer задаёт viewport 800 на 600 по умолчанию. defaultViewport: null отменяет эту эмуляцию, но не подтверждает размер системного экрана, состояние оконного менеджера или физические размеры монитора. Записывайте window.innerWidth, window.innerHeight, screen.width и screen.height.

BrowserContext изолирует cookies и хранилище от других контекстов того же процесса. Он не выбирает другой бинарный файл, не создаёт публичный IP, не разрешает сбор и не устанавливает личность. Идентификатор контекста и политика хранения относятся к входным условиям, а не к доказательствам доступа.

Доступный только для чтения navigator.webdriver является булевым значением страницы. MDN описывает условия, при которых Chrome под автоматическим управлением его предоставляет. true или false может объяснить различие. Детектор использует и другие сигналы, а сервер получает данные, недоступные странице. Разбор границ патчей Puppeteer и Playwright отделяет изменение JavaScript от поведения, которое патч не контролирует.

Разделяйте установку и выполнение. Файлы конфигурации Puppeteer задают загрузку и кеш; puppeteer-core их игнорирует. Изменение кеша может изменить установленный бинарный файл, но не является наблюдением viewport или хранилища. Фиксируйте выбранный исполняемый файл и версии пакетов.

Поля записи

До запуска создайте запись: идентификатор, версия пакета, выбранный исполняемый файл, строка версии, имя аргумента профиля без секретных байтов, режим headless, viewport, ревизия каталога и собственный источник. Эти поля определяют сравнимость двух JSON. Не включайте cookies, токены, байты профиля и строки запроса с авторизацией.

Настройки и наблюдения

ВходОбластьНаблюдения и диагностикаЧто нельзя установить
executablePathПроцессВерсия и доступные APIЗагрузку запрошенного файла или принятие сервером
headlessПроцессViewport, отрисовка, выбранные свойстваДоверие, разрешение или вердикт
defaultViewportЭмуляция страницыinnerWidth, innerHeight, параметры экранаФизические размеры монитора
userDataDirПостоянное состояниеДоступные cookies и хранилищеПрофиль, публичный IP или владение аккаунтом
BrowserContextХранилище контекстаЛокальные cookies и изоляцияНовый бинарный файл, сетевую личность или разрешение
navigator.webdriverПоле страницыБулево значение только для чтенияПолный отпечаток или решение сервера

Приёмка каталога

Проверьте источник HTTP или HTTPS, принадлежащий проекту, с завершающим /, без учётных данных, запроса и фрагмента. После навигации маршрут должен оставаться на том же источнике. В строке допускаются ровно одно название и одна цена установленного десятичного формата. Отклоняйте дубликаты, ссылки другого источника, отсутствие валюты и неожиданные пути.

Воспроизводимость и закрытие

Используйте новый RUN_USER_DATA_DIR для независимого сравнения, если не изучаете постоянное состояние. Фиксируйте профиль и копируйте только разрешённые данные каталога. Ограничивайте время навигации и различайте таймаут до и после ответа. Таймаут описывает транспорт или готовность страницы, а не доказывает отказ браузеру.

Манифест входных условий

Рядом с записью храните версию Puppeteer, дайджест файла фиксации пакетов, версию исполняемого файла, режим, viewport, политику контекста, ревизию каталога и время старта. Пути недостаточно: файл можно заменить на месте, а каталог сохраняет старое состояние. Манифест фиксирует условия без копирования профилей и аккаунтов.

Сохраняйте типы: headless равен true, false или 'shell'; defaultViewport равен null или объекту с числовыми размерами. Для userDataDir используйте обезличенный идентификатор вместо частного пути. У переменной окружения записывайте имя и разрешённое значение. Не приравнивайте пропущенную настройку к явному значению без версии Puppeteer.

Навигация и ответ

Записывайте запрошенный и конечный URL, число перенаправлений, HTTP-статус и время до domcontentloaded. Это разные сведения: страница своего источника может быть ошибкой, а 200 может не пройти схему. Таймаут до первого ответа отличается от таймаута при загрузке скрипта. Не сводите транспорт, навигацию и данные к одной метке.

Каталогу нужен определённый сигнал готовности. Две фиксированные строки сравнивать проще, чем растущий при чтении список. Дождитесь маркера, затем проверяйте количество строк. Отсутствие сетевой активности не доказывает завершение приложения: аналитика, опросы и Service Workers могут продолжаться; страница ошибки может сразу стать тихой.

Проверка данных

До записи проверяйте ровно одно название, одну цену и трёхбуквенную валюту на строку. Исходный текст при необходимости оставляйте в защищённой локальной диагностике; общая запись может содержать обезличенный дайджест и результат. Две принятые строки и ноль строк различаются, но ничего не доказывают об иных маршрутах и сервисах.

Указывайте поле и правило: price-format, currency-code, duplicate-item, missing-name полезнее, чем schema=false. Добавляйте ревизию селекторов и дайджест каталога: изменение разметки может вызвать ошибку при неизменных входных условиях браузера.

Расчёт различий

После получения обеих записей отсортируйте идентификаторы по ключу, нормализуйте завершающие слеши URL и сравнивайте размеры как числа. Неизмеренные поля храните отдельно. Следующий формат гипотетический, его размеры не являются результатом запуска:

{
  "changedOption": "defaultViewport",
  "before": { "innerWidth": 800, "innerHeight": 600 },
  "after": { "innerWidth": 1280, "innerHeight": 720 },
  "same": ["origin", "itemCount", "currency"],
  "changed": ["innerWidth", "innerHeight"],
  "notObserved": ["screenX"],
  "interpretation": "The fixture read a different emulated viewport."
}

Интерпретация называет наблюдение и область действия, не делая выводов о человеке, детекторе, владельце профиля или политике сайта. При разных версиях исполняемого файла или каталога сначала ставьте not-comparable. Два изменённых входа означают другой эксперимент.

Сравнение постоянного состояния

Для изучения постоянного состояния меняйте только его. A использует новый каталог; закройте браузер и запустите B с тем же каталогом. Запишите сообщённые собственным сайтом ключи, но не значения cookies и токенов. Третий запуск с новым каталогом проверяет зависимость от сохранения состояния, а не владение аккаунтом или разрешение.

Изоляция контекстов проверяется отдельно: создайте два контекста в одном процессе, загрузите один источник и запишите доступность маркера каждому. Закройте их и повторите в новом процессе, если изучаете повторное использование процесса. Результат описывает хранилище каталога, не изменение бинарного файла, сетевого пути или решения сервера.

Версии и возврат

Фиксируйте пакет и исполняемый файл на время сравнения. При изменении версии создавайте новую пару записей, даже если настройки те же. Обновление может менять отрисовку, значения по умолчанию или поля. Сохраняйте прежнее нормализованное различие и причину перехода на новую версию.

Возврат требует восстановления файла фиксации пакетов, исполняемого файла, ссылки на профиль, аргументов, viewport, политики контекста и каталога. Одного headless или defaultViewport недостаточно при другом бинарном файле или хранилище. Версионируйте каталог и зависимости, отделяя ссылки на профиль от секретного содержимого.

Ограниченный пример с одной переменной

Собственная страница предоставляет две строки data-testid="item" на /catalog, с уникальным data-id, названием, ценой и валютой. Только после готовности обеих строк каталог устанавливает data-ready="true" на data-testid="catalog". Скрипт иллюстративный, не отчёт о запуске. Он пишет данные после проверки ответа, URL, готовности и схемы.

import puppeteer from 'puppeteer-core';
import fs from 'node:fs/promises';

const origin = new URL(process.env.OWNED_CATALOG_ORIGIN ?? '');
const executablePath = process.env.BOTBROWSER_EXEC_PATH;
const profilePath = process.env.BOT_PROFILE_PATH;
const mode = process.env.HEADLESS_MODE ?? 'true';
const viewportMode = process.env.DEFAULT_VIEWPORT ?? '800x600';
if (
  !['http:', 'https:'].includes(origin.protocol) ||
  origin.username ||
  origin.password ||
  origin.pathname !== '/' ||
  origin.search ||
  origin.hash
)
  throw new Error('OWNED_CATALOG_ORIGIN must be a plain HTTP(S) origin');
if (!['true', 'false'].includes(mode)) throw new Error('HEADLESS_MODE must be true or false');
if (!['null', '800x600'].includes(viewportMode)) throw new Error('invalid DEFAULT_VIEWPORT');
if (!executablePath || !profilePath || !process.env.RUN_USER_DATA_DIR)
  throw new Error('browser inputs and a dedicated RUN_USER_DATA_DIR are required');
const viewport = viewportMode === 'null' ? null : { width: 800, height: 600 };
const headless = mode === 'true';
const browser = await puppeteer.launch({
  browser: 'chrome',
  executablePath,
  headless,
  defaultViewport: viewport,
  args: [`--bot-profile=${profilePath}`],
  userDataDir: process.env.RUN_USER_DATA_DIR,
});
const diagnostics = [];
try {
  const context = await browser.createBrowserContext();
  const page = await context.newPage();
  const assertRoute = () => {
    const url = new URL(page.url());
    if (url.origin !== origin.origin || url.pathname !== '/catalog' || url.search || url.hash)
      throw new Error('unexpected catalogue URL');
  };
  const started = Date.now();
  const response = await page.goto(new URL('catalog', origin).href, {
    waitUntil: 'domcontentloaded',
    timeout: 15000,
  });
  assertRoute();
  if (!response || !response.ok()) throw new Error(`HTTP response rejected: ${response?.status()}`);
  const navigationMs = Date.now() - started;
  await page.waitForSelector('[data-testid="catalog"][data-ready="true"]', { timeout: 5000 });
  const items = await page.$$eval('[data-testid="item"]', nodes =>
    nodes.map(node => {
      if (
        node.querySelectorAll('[data-testid="item-name"]').length !== 1 ||
        node.querySelectorAll('[data-testid="item-price"]').length !== 1
      )
        throw new Error('name or price cardinality rejected');
      return {
        id: node.getAttribute('data-id'),
        name: node.querySelector('[data-testid="item-name"]')?.textContent?.trim(),
        price: node.querySelector('[data-testid="item-price"]')?.textContent?.trim(),
        currency: node.querySelector('[data-testid="item-price"]')?.getAttribute('data-currency'),
      };
    })
  );
  if (
    items.length !== 2 ||
    new Set(items.map(item => item.id)).size !== 2 ||
    items.some(
      item =>
        !item.id || !item.name || !/^\d+\.\d{2}$/.test(item.price ?? '') || !/^[A-Z]{3}$/.test(item.currency ?? '')
    )
  )
    throw new Error('fixture row schema rejected');
  const observed = await page.evaluate(() => ({
    innerWidth: window.innerWidth,
    innerHeight: window.innerHeight,
    screenWidth: screen.width,
    screenHeight: screen.height,
    webdriver: navigator.webdriver,
  }));
  assertRoute();
  diagnostics.push({
    finalUrl: page.url(),
    status: response.status(),
    navigationMs,
    redirectCount: response.request().redirectChain().length,
    itemCount: items.length,
  });
  await fs.writeFile(
    'puppeteer-scrape-record.json',
    JSON.stringify(
      {
        inputs: { headless, defaultViewport: viewport },
        controls: { userDataPolicy: 'fresh-empty-per-run', contextPolicy: 'new-isolated-context' },
        observed,
        items,
        diagnostics,
      },
      null,
      2
    ),
    { flag: 'wx' }
  );
} finally {
  await browser.close();
}

Фиксируйте источник, исполняемый файл, профиль, каталог, зависимости и селекторы для A и B. Меняйте только изучаемую настройку HEADLESS_MODE или DEFAULT_VIEWPORT. Каждый процесс получает отдельный, изначально пустой RUN_USER_DATA_DIR. Пути различаются, но политика одинакова: fresh-empty-per-run. Это не утверждение о совпадении всех необработанных входов. Проверьте политику до старта. Пример сравнивает headless или viewport, не постоянное состояние.

В примере HEADLESS_MODE принимает только true и false: headless-shell изменил бы ещё и бинарный файл. Запускайте из разных выходных каталогов: flag: 'wx' запрещает перезапись. Перед меткой changedOption проверьте одно различие в inputs и совпадение обеих политик контроля.

Скрипт пишет только успешную запись. Отдельно сохраняйте манифест: скрипт не определяет идентификаторы пакета, исполняемого файла, профиля, каталога или селекторов. При ошибке сохраняйте код завершения и текст ошибки, затем определяйте этап по категориям ниже. Отсутствие JSON или JSON предыдущего запуска не доказывает текущий успех. Ошибка запуска, навигации, готовности или схемы остаётся неудачной попыткой.

Новый контекст начинает с изолированным хранилищем: постоянный userDataDir не передаёт ему cookies контекста по умолчанию. Для сравнения сохранения состояния используйте последний последовательно либо явно устанавливайте одинаковое состояние в каждом новом контексте. Справочник контекстов, страниц и закрытия объясняет владение; закрытие браузера закрывает страницы и контексты, в том числе при ошибке создания страницы или проверки.

Область и ограничения наблюдений

У каждого поля своя область: viewport относится к эмуляции, userDataDir к постоянному состоянию, headless к режиму процесса, navigator.webdriver к одному булеву значению. Ни одно поле не является полным отпечатком и не определяет само по себе человека, устройство, владельца или вердикт.

Различайте same, changed, not-observed. Отсутствующее поле не равно false: API может быть недоступен, разрешение отклонено или поле отсутствует в каталоге. Разделяйте HTTP и принятые деловые данные. Ответ 200 бывает пустым или неверным, а корректная запись не гарантирует ответ другого маршрута.

До интерпретации сравнивайте исполняемый файл, версию Puppeteer, аргументы, каталог, создание контекста, URL, статус, ревизию каталога и дайджест селекторов. Иначе изменение бинарного файла, старые cookies или разметку можно ошибочно приписать viewport.

Категории ошибок

Неверный executablePath означает ошибку старта; отсутствующий профиль, ошибку входа; общий userDataDir, нарушение изоляции; конечный URL вне источника, ошибку разрешения или навигации; 200 без принятых строк, ошибку схемы. Сохраняйте категории вместо одинакового повтора команды при любой ошибке.

Если puppeteer-core игнорирует ожидаемый файл конфигурации, проверяйте явные аргументы и выбранный бинарный файл. При неожиданных размерах с defaultViewport: null записывайте четыре размера и среду отображения без вывода о физическом мониторе. При изменении navigator.webdriver фиксируйте режим и аргументы, не переписывая свойство.

Вопросы

Что меняет headless?

Он выбирает режим выполнения браузера. Страница видит часть последствий, сервер может использовать другие сигналы. Запись описывает различия без обещаний результата детектора или сайта.

userDataDir является файлом профиля?

Нет, это каталог постоянных данных. У входного профиля и каталога разные сроки жизни и владение; явно записывайте оба.

Новый BrowserContext создаёт новую личность?

Нет. Он изолирует данные сеанса в браузере, не предоставляет разрешений, не меняет публичный IP и не устанавливает владение сеансом.

Зачем записывать navigator.webdriver?

Это конкретное видимое поле, способное объяснить различие страницы. Оно не является вердиктом и не должно удаляться или переписываться для диагностики.

Источники

Практический вывод

Меняйте одну настройку запуска или страницы при фиксированных собственном каталоге, исполняемом файле, профиле, контексте, версиях и селекторах. Сохраняйте точные наблюдения и диагностику, классифицируйте ошибки по области, оставляйте неизвестное неизвестным. Различие объясняет прочитанное страницей, не отсутствие обнаружения, личность владельца профиля или обязательное принятие запроса.

Далее: контексты, страницы и закрытие Puppeteer и границы патчей Puppeteer и Playwright.

#Puppeteer#веб-скрейпинг#Browser Automation#сигналы браузера

Эта статья входит в руководство: Начало работы с автоматизацией браузера: карта

Выполните ту же проверку в BotBrowser

Загрузите профиль, сохраните внутри браузера те сигналы, о которых только что прочитали, и подтвердите результат на своей машине до раскатки.