Библиотека · Автономные агенты и мультиагентные системы

Браузерные агенты — Browserbase, Stagehand и автоматизация веба

Инженер60 минОбновлено: октябрь 2026
73 из 105 в библиотеке

Модуль: 18. Advanced Orchestration | Время: ~25 мин теории + 35 мин практики


Суть урока

🎨 Образ: Представь, что у тебя есть невидимый сотрудник, который не спит, не устаёт и не просит зарплату. Ты говоришь ему: «Зайди на сайт конкурента, найди все цены на ноутбуки, сохрани в таблицу и пришли мне в 9 утра». Он исполняет — каждый день, 24/7, без ошибок и жалоб.

Это и есть браузерный агент — AI-система, которая управляет настоящим браузером, читает страницы так же, как человек, и принимает решения о следующем действии на основе того, что видит. Не просто скрипт с фиксированными CSS-селекторами, а настоящий интеллект, понимающий смысл страницы.

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


Ключевые концепции

  • Браузерный агент vs классическая автоматизация — AI понимает смысл страницы, а не просто ищет CSS-селекторы
  • Browserbase — облачная инфраструктура браузеров для AI-агентов с антидетект-функциями
  • Stagehand — SDK от Browserbase поверх Playwright с методами act(), extract(), observe(), управляемыми LLM
  • Session replay — запись и воспроизведение сессий для дебага агентов
  • Антидетект-техники — stealth-режим, жилые прокси, обход CAPTCHA
  • Этика скрапинга — публичные данные vs приватные, Terms of Service, PII
  • Монетизация — услуги по сбору и мониторингу данных (формат услуги, а не гарантия дохода)

Теория

Почему браузерные агенты — это не Selenium 2.0

Когда в 2004 году появился Selenium, автоматизация веба строилась по одному принципу: программист руками находит CSS-селектор или XPath-путь к нужному элементу и говорит скрипту: «нажми на #buy-button». Это работало, пока сайты не меняли вёрстку. Но стоило разработчикам поменять класс кнопки — скрипт ломался.

Puppeteer (2017) и Playwright (2020) сделали этот подход быстрее и надёжнее, но принцип остался тем же: жёсткие инструкции на основе структуры DOM. Если страница изменилась — автоматизация сломана.

Браузерный агент думает иначе. Вместо «нажми на элемент с id=submit» он получает задачу «оформи заказ» и сам разбирается, что для этого нужно сделать. Он читает текст на странице, понимает контекст, видит, что кнопка называется «Оформить заказ» или «Checkout» — и нажимает на неё. Если вёрстка поменялась, агент просто переработает свой план.

🎨 Образ: Классический скрипт — это слепой рабочий, которому дали точные координаты: «повернись на 45 градусов, сделай три шага вперёд, потяни за ручку». Браузерный агент — это зрячий сотрудник, которому сказали: «открой дверь» — и он сам найдёт её на любом фоне.

Browserbase: облачный браузер для AI

Browserbase — это управляемая облачная инфраструктура для запуска браузеров. Не просто headless Chrome на твоём сервере, а полноценная платформа с рядом ключевых возможностей:

Что даёт Browserbase:

  1. Управляемые браузеры — не нужно настраивать Chromium, версии, зависимости. Browserbase запускает браузеры в своей инфраструктуре, ты подключаешься через WebSocket.

  2. Session Replay — каждую сессию агента можно воспроизвести как видео. Незаменимо для дебага: видишь буквально то, что видел агент в момент ошибки.

  3. Стелс-режим — браузеры настроены так, чтобы выглядеть как обычный пользователь: правильные заголовки, реалистичный отпечаток браузера. Базовые антибот-проверки это часто проходит, серьёзные защиты — не всегда.

  4. Параллельность — можно запускать много сессий одновременно (предел зависит от тарифа). Мониторить десятки сайтов сразу — обычная задача.

  5. Жилые прокси — возможность выходить через реальные IP-адреса пользователей разных стран.

Цены: у Browserbase есть бесплатный тариф и платные, которые различаются числом браузерных часов в месяц и числом браузеров, работающих одновременно. Для проверки идеи хватает бесплатного тарифа. Актуальные тарифы и цены: browserbase.com/pricing.

Stagehand: AI-Playwright

Stagehand — это open-source SDK от команды Browserbase, который добавляет AI-интеллект к автоматизации браузера (изначально поверх Playwright). Если Playwright — это руки (инструменты управления браузером), то Stagehand — это мозг, который решает, что делать руками.

Про версии. В версии 3 методы act(), extract() и observe() вызываются у самого объекта stagehand, а страницу берут из stagehand.context.pages()[0]. В версии 2 они вызывались у page (page.act(...)). Примеры ниже написаны под версию 3; перед работой сверься с документацией установленной версии: docs.stagehand.dev.

Три ключевых метода:

act(instruction) — выполни действие

typescript
await stagehand.act('Нажми на кнопку "Войти"');
await stagehand.act('Заполни поле email адресом test@example.com');
await stagehand.act('Прокрути страницу вниз до раздела "Цены"');

Stagehand берёт твою инструкцию на естественном языке, смотрит на страницу через screenshot или DOM, определяет нужный элемент и выполняет действие. Если элемент переехал — не проблема, AI найдёт его снова.

extract(instruction, schema) — извлеки данные

typescript
const products = await stagehand.extract(
  'Найди все товары с ценами на странице',
  z.object({
    items: z.array(z.object({
      name: z.string(),
      price: z.number(),
      inStock: z.boolean(),
    }))
  })
);

Метод возвращает структурированные данные (валидируется через Zod), извлечённые со страницы. AI понимает, что такое «цена» и «наличие», даже если разные сайты показывают это по-разному.

observe(instruction) — посмотри и скажи

typescript
const elements = await stagehand.observe(
  'Какие кнопки доступны для действий с этим товаром?'
);
// возвращает список найденных элементов и предлагаемых действий,
// например кнопки «Добавить в корзину», «Купить сейчас», «Сравнить»

Наблюдение без действия — полезно для принятия решений в агентном цикле.

Полный пример: мониторинг цен конкурента

typescript
import { Stagehand } from '@browserbasehq/stagehand';
import { z } from 'zod';

const PriceSchema = z.object({
  products: z.array(z.object({
    name: z.string().describe('Название товара'),
    price: z.number().describe('Цена в рублях'),
    oldPrice: z.number().nullable().describe('Старая цена со скидкой'),
    inStock: z.boolean().describe('Есть ли в наличии'),
    url: z.string().describe('Ссылка на товар'),
  }))
});

async function monitorCompetitorPrices(competitorUrl: string) {
  // Ключи Browserbase и модели читаются из .env / переменных окружения
  const stagehand = new Stagehand({
    env: 'BROWSERBASE',
    model: 'anthropic/claude-sonnet-5-5',   // актуальные модели: страница «Актуальное сейчас»
    verbose: 1,
  });

  await stagehand.init();
  const page = stagehand.context.pages()[0];

  try {
    // Переходим на страницу каталога
    await page.goto(competitorUrl);
    await page.waitForLoadState('networkidle');

    // Если нужно принять куки — делаем это
    const cookieBanner = await stagehand.observe(
      'Есть ли баннер о куки или GDPR, который нужно закрыть?'
    );
    if (cookieBanner.length > 0) {
      await stagehand.act('Нажми "Принять все" или закрой баннер о куки');
    }

    // Извлекаем товары с текущей страницы
    const result = await stagehand.extract(
      'Найди все товары в каталоге: название, цену, старую цену и наличие',
      PriceSchema
    );

    // Проверяем, есть ли пагинация
    const hasNextPage = await stagehand.observe(
      'Есть ли кнопка "Следующая страница" или "Ещё товары"?'
    );

    if (hasNextPage.length > 0) {
      await stagehand.act('Нажми на следующую страницу');
      await page.waitForLoadState('networkidle');
      
      const nextPageResult = await stagehand.extract(
        'Найди все товары на этой странице',
        PriceSchema
      );
      
      result.products.push(...nextPageResult.products);
    }

    return result.products;

  } finally {
    await stagehand.close();
  }
}

// Запуск
const prices = await monitorCompetitorPrices('https://competitor.ru/catalog/laptops');
console.log(`Найдено ${prices.length} товаров`);

Сравнение с Playwright MCP

В уроке Автоматизация браузера мы работали с Playwright и Claude Code — инструментом, который позволяет управлять браузером в рамках диалога с Claude. Это отличный инструмент для интерактивной автоматизации под руководством человека.

Характеристика Playwright MCP Stagehand + Browserbase
Управление Интерактивное (через Claude Code) Автономное (агент решает сам)
Инфраструктура Локальный браузер Облако (много параллельных)
Антидетект Базовый Расширенный (stealth + прокси, без гарантий)
Session replay Нет Есть
Масштабирование 1 браузер Много одновременно (по тарифу)
Лучше для Разовых задач с участием человека Регулярных автономных задач

Для продакшн-агента, который работает по расписанию и обрабатывает десятки сайтов — выбор за Stagehand. Для интерактивного исследования сайта в Claude Code — Playwright MCP удобнее.

DIY-подход: Puppeteer + Claude API

Если не хочешь платить за Browserbase, можно собрать аналог самостоятельно. Плагин stealth для puppeteer-extra развивается нерегулярно: перед использованием проверь, что он ещё работает:

typescript
import puppeteer from 'puppeteer-extra';
import StealthPlugin from 'puppeteer-extra-plugin-stealth';
import Anthropic from '@anthropic-ai/sdk';

puppeteer.use(StealthPlugin());

const client = new Anthropic();

async function aiScrapePage(url: string, task: string) {
  const browser = await puppeteer.launch({ headless: true });
  const page = await browser.newPage();
  
  // Имитация реального браузера
  await page.setUserAgent(
    'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36'
  );
  
  await page.goto(url, { waitUntil: 'networkidle2' });
  
  // Делаем скриншот и передаём Claude
  const screenshot = await page.screenshot({ encoding: 'base64' });
  const htmlContent = await page.content();
  
  const response = await client.messages.create({
    model: 'claude-sonnet-5-5',   // актуальные модели: страница «Актуальное сейчас»
    max_tokens: 2000,
    messages: [{
      role: 'user',
      content: [
        {
          type: 'image',
          source: { type: 'base64', media_type: 'image/png', data: screenshot as string }
        },
        {
          type: 'text',
          text: `Задача: ${task}\n\nHTML страницы:\n${htmlContent.substring(0, 5000)}\n\nВерни результат в JSON.`
        }
      ]
    }]
  });
  
  await browser.close();
  return response.content.map((b) => (b.type === 'text' ? b.text : '')).join('');
}

Этот подход бесплатный по инфраструктуре (только API Claude), но не масштабируется так же хорошо и требует больше настройки.

Антидетект: как не попасть в бан

Сайты используют несколько уровней защиты от ботов:

Уровень 1 — базовый (обходится легко):

  • Проверка User-Agent — решается установкой реального UA
  • Слишком быстрые запросы — решается рандомными паузами (Math.random() * 2000 + 500 ms)
  • Отсутствие cookies/localStorage — решается нормальным браузером

Уровень 2 — продвинутый (требует усилий):

  • Fingerprinting браузера (canvas, WebGL, fonts) — Browserbase и puppeteer-stealth частично скрывают
  • Анализ поведения мыши — нужны реалистичные движения
  • IP-репутация — жилые прокси (residential proxies) от providers вроде Bright Data или Oxylabs

Уровень 3 — серьёзная защита:

  • CAPTCHA (reCAPTCHA v3, hCaptcha) — существуют платные сервисы решения вроде 2captcha.com или CapSolver (цену смотри на их сайтах)
  • Cloudflare Bot Management — обход не гарантирован ни одним сервисом

Важно. Обход защиты от ботов часто нарушает условия использования сайта, а в ряде стран и закон. Урок показывает механику, чтобы ты понимал, как это устроено. Если у сайта есть официальный API или можно договориться о доступе, это надёжнее и безопаснее.

typescript
// Схематичный пример интеграции 2captcha (проверь API сервиса и условия сайта)
import Captcha2 from '2captcha-ts';
const solver = new Captcha2.Solver(process.env.CAPTCHA_API_KEY);

// При обнаружении CAPTCHA
const siteKey = await page.evaluate(() => 
  document.querySelector('[data-sitekey]')?.getAttribute('data-sitekey')
);

if (siteKey) {
  const result = await solver.recaptcha({
    pageurl: page.url(),
    googlekey: siteKey,
  });
  
  await page.evaluate((token) => {
    (window as any).grecaptcha?.enterprise?.execute?.(token);
  }, result.data);
}

Этика и легальность: что можно, что нельзя

🎨 Образ: Скрапинг похож на посещение публичной библиотеки. Книги открыты для всех — можно читать, делать заметки, анализировать. Но нельзя вырывать страницы, фотографировать закрытые архивы или притворяться сотрудником.

Что обычно можно (публичные данные):

  • ✅ Цены на публичных страницах магазинов
  • ✅ Публично доступные объявления (недвижимость, работа)
  • ✅ Новостные статьи (для агрегации, не для перепубликации)
  • ✅ Данные из публичных API
  • ✅ Информация о компаниях из открытых источников

Что нельзя (юридические риски):

  • ❌ PII — личные данные пользователей (email, телефоны из закрытых разделов)
  • ❌ Контент за paywall без подписки
  • ❌ Данные, скрапинг которых прямо запрещён в Terms of Service
  • ❌ Нагрузка, мешающая работе сайта (DDoS-like behavior)
  • ❌ Обход систем аутентификации

Перед запуском всегда проверяй robots.txt и Terms of Service целевого сайта. В ЕС — дополнительно смотри GDPR, в США — CFAA и scraping-решения по LinkedIn vs hiQ.

Практическое правило: если информация отображается для любого неавторизованного пользователя без регистрации — скорее всего, скрапинг публичных данных допустим. Если нужен логин — уже серая зона.

Монетизация: продажа дата-фидов

Браузерные агенты — это не только инструмент для собственных нужд. Это продукт, который можно продавать.

Модели продажи:

  1. Регулярный поток данных — клиент платит за периодическую выгрузку. Например, ежедневный дамп цен конкурентов в определённой нише. Агента настраиваешь один раз, дальше он работает по расписанию, а ты следишь за ошибками и правишь сценарий, когда сайт меняется.

  2. Разовый проект по сбору данных — клиент платит за единичную выгрузку. База компаний в определённом регионе, список потенциальных партнёров, анализ рынка.

  3. Monitoring as a service — отслеживание изменений на сайтах (новые вакансии, изменения цен, появление новых конкурентов). Клиент получает алерты в Telegram или email.

  4. White-label решение — продаёшь не данные, а инструмент. Настраиваешь агента для клиента, он сам его использует. Разовая оплата + поддержка.

Цену задают рынок и твои затраты (серверы, тариф Browserbase, токены, время на поддержку). Заработок в этой нише не гарантирован: прикинь расходы и спрос на своём рынке по урокам Упаковка предложения и Цены и монетизация.

🎨 Образ: Представь фермера, который установил автоматические оросительные системы на нескольких полях. Поля работают сами, фермер только проверяет их. Браузерный агент — это твоя оросительная система, а данные — урожай, который клиент готов оплатить.


Практика

Задача: агент мониторинга цен с уведомлениями в Telegram

Построим агент, который раз в час проверяет цены на товары конкурента и отправляет алерт, если цена снизилась более чем на 5%.

Шаг 1: Установка зависимостей

bash
mkdir price-monitor-agent && cd price-monitor-agent
npm init -y
npm install @browserbasehq/stagehand zod dotenv node-telegram-bot-api
npm install -D typescript @types/node tsx

Создай .env:

env
BROWSERBASE_API_KEY=bb_live_xxxx
BROWSERBASE_PROJECT_ID=prj_xxxx
TELEGRAM_BOT_TOKEN=xxxx
TELEGRAM_CHAT_ID=xxxx
ANTHROPIC_API_KEY=sk-ant-xxxx

Шаг 2: Схема данных и конфигурация

Создай src/types.ts:

typescript
import { z } from 'zod';

export const ProductSchema = z.object({
  name: z.string(),
  price: z.number(),
  oldPrice: z.number().nullable(),
  inStock: z.boolean(),
  sku: z.string().optional(),
});

export type Product = z.infer<typeof ProductSchema>;

export const MonitorConfig = {
  targetUrl: 'https://example-shop.ru/catalog/laptops',
  checkIntervalMinutes: 60,
  priceDropThresholdPercent: 5,
};

Шаг 3: Функция скрапинга

Создай src/scraper.ts:

typescript
import { Stagehand } from '@browserbasehq/stagehand';
import { z } from 'zod';
import { ProductSchema, type Product } from './types';

export async function scrapeProducts(url: string): Promise<Product[]> {
  // Ключи Browserbase и модели читаются из .env (файл .env загружает dotenv)
  const stagehand = new Stagehand({
    env: 'BROWSERBASE',
    model: 'anthropic/claude-sonnet-5-5',
  });

  await stagehand.init();
  const page = stagehand.context.pages()[0];

  try {
    await page.goto(url);
    await page.waitForLoadState('networkidle');

    // Обработка куки-баннеров
    const cookieBanner = await stagehand.observe(
      'Есть ли баннер о куки или согласии, который нужно принять?'
    );
    if (cookieBanner.length > 0) {
      await stagehand.act('Прими или закрой баннер о куки');
      await page.waitForTimeout(1000);
    }

    // Извлекаем данные о товарах
    const result = await stagehand.extract(
      `
        Найди все товары на странице каталога.
        Для каждого извлеки: точное название, текущую цену числом,
        старую цену (если есть скидка), наличие на складе.
        Цены должны быть числами без символов валют.
      `,
      z.object({
        products: z.array(ProductSchema)
      })
    );

    return result.products;

  } finally {
    await stagehand.close();
  }
}

Шаг 4: Хранение и сравнение цен

Создай src/storage.ts:

typescript
import fs from 'fs/promises';
import path from 'path';
import type { Product } from './types';

const DATA_FILE = path.join(process.cwd(), 'prices.json');

export interface PriceRecord {
  timestamp: string;
  products: Product[];
}

export async function saveProducts(products: Product[]): Promise<void> {
  const record: PriceRecord = {
    timestamp: new Date().toISOString(),
    products,
  };
  await fs.writeFile(DATA_FILE, JSON.stringify(record, null, 2));
}

export async function loadPreviousProducts(): Promise<Product[] | null> {
  try {
    const data = await fs.readFile(DATA_FILE, 'utf-8');
    const record: PriceRecord = JSON.parse(data);
    return record.products;
  } catch {
    return null; // Первый запуск
  }
}

export interface PriceDrop {
  product: Product;
  oldPrice: number;
  newPrice: number;
  dropPercent: number;
}

export function findPriceDrops(
  current: Product[],
  previous: Product[],
  thresholdPercent: number
): PriceDrop[] {
  const drops: PriceDrop[] = [];
  
  for (const currentProduct of current) {
    const prevProduct = previous.find(p => p.name === currentProduct.name);
    if (!prevProduct) continue;
    
    const dropPercent = ((prevProduct.price - currentProduct.price) / prevProduct.price) * 100;
    
    if (dropPercent >= thresholdPercent) {
      drops.push({
        product: currentProduct,
        oldPrice: prevProduct.price,
        newPrice: currentProduct.price,
        dropPercent,
      });
    }
  }
  
  return drops.sort((a, b) => b.dropPercent - a.dropPercent);
}

Шаг 5: Уведомления и главный цикл

Создай src/index.ts:

typescript
import 'dotenv/config';
import TelegramBot from 'node-telegram-bot-api';
import { scrapeProducts } from './scraper';
import { saveProducts, loadPreviousProducts, findPriceDrops } from './storage';
import { MonitorConfig } from './types';

const bot = new TelegramBot(process.env.TELEGRAM_BOT_TOKEN!);

async function sendAlert(drops: ReturnType<typeof findPriceDrops>) {
  const chatId = process.env.TELEGRAM_CHAT_ID!;
  
  let message = `🔥 *Снижение цен обнаружено!*\n\n`;
  
  for (const drop of drops) {
    message += `📦 *${drop.product.name}*\n`;
    message += `💰 ${drop.oldPrice.toLocaleString()} → ${drop.newPrice.toLocaleString()} руб\n`;
    message += `📉 Снижение: *${drop.dropPercent.toFixed(1)}%*\n`;
    message += drop.product.inStock ? '✅ Есть в наличии\n' : '❌ Нет в наличии\n';
    message += '\n';
  }
  
  await bot.sendMessage(chatId, message, { parse_mode: 'Markdown' });
}

async function runCheck() {
  console.log(`[${new Date().toISOString()}] Запуск проверки цен...`);
  
  try {
    // Скрапинг текущих цен
    const currentProducts = await scrapeProducts(MonitorConfig.targetUrl);
    console.log(`Найдено товаров: ${currentProducts.length}`);
    
    // Сравнение с предыдущими данными
    const previousProducts = await loadPreviousProducts();
    
    if (previousProducts) {
      const drops = findPriceDrops(
        currentProducts,
        previousProducts,
        MonitorConfig.priceDropThresholdPercent
      );
      
      if (drops.length > 0) {
        console.log(`Найдено снижений цен: ${drops.length}`);
        await sendAlert(drops);
      } else {
        console.log('Значимых изменений цен не обнаружено');
      }
    } else {
      console.log('Первый запуск — базовые цены сохранены');
    }
    
    // Сохраняем текущие цены как эталон
    await saveProducts(currentProducts);
    
  } catch (error) {
    console.error('Ошибка при проверке:', error);
    await bot.sendMessage(
      process.env.TELEGRAM_CHAT_ID!,
      `⚠️ Ошибка агента мониторинга: ${error}`
    );
  }
}

// Запуск и повтор по расписанию
async function main() {
  console.log('Агент мониторинга запущен');
  
  // Первый запуск сразу
  await runCheck();
  
  // Затем по расписанию
  setInterval(
    runCheck,
    MonitorConfig.checkIntervalMinutes * 60 * 1000
  );
}

main().catch(console.error);

Запуск:

bash
npx tsx src/index.ts

Для продакшна — простой VPS с pm2 start или запуск одного прохода по расписанию через cron вместо setInterval.


Инструменты и ресурсы

Инструмент Назначение Ссылка
Browserbase Облачные управляемые браузеры для агентов browserbase.com
Stagehand AI-powered Playwright SDK (open source) github.com/browserbase/stagehand
Playwright Базовый движок автоматизации браузера playwright.dev
Puppeteer + Stealth DIY-альтернатива с антидетект плагином github.com/berstend/puppeteer-extra
2captcha Сервис решения CAPTCHA (цена на сайте) 2captcha.com
CapSolver Альтернатива 2captcha с AI capsolver.com
Bright Data Жилые прокси для обхода блокировок brightdata.com

Ключевые выводы

«Браузерный агент — это не улучшенный скрипт. Это сотрудник, который понимает цель, а не просто следует инструкциям. Когда сайт меняется — человек адаптируется. Агент тоже.»

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

«Публичные данные — это как витрина магазина. Смотреть и анализировать — твоё право. Но ломать замок или копировать чужое содержимое в коммерческих целях — уже другая история. Знай границу.»


Следующий урок

→ Мультиагентная оркестрация — LangGraph, CrewAI и Mastra

Если один агент — это один сотрудник, то мультиагентная система — это целый отдел. Разберём, как агенты координируются, передают задачи друг другу и как строить pipeline из десятков специализированных AI-воркеров. LangGraph для stateful workflow, CrewAI для role-based команд, Mastra как TypeScript-фреймворк с открытым кодом.

Отметка хранится только в этом браузере и никуда не отправляется. Мой прогресс