EvolCode
треки/ИИ-агенты·01 / 07
15 мин чтения

Браузерный агент за 30 минут — Playwright + Claude

Парсинг сайтов через regex и cheerio — каменный век. JavaScript-сайты не парсятся, формы требуют скриптов, капчи ломают всё. Playwright — это полноценный браузер которым управляешь из кода. Подключаем к нему Claude как «мозги» — получаем агента который смотрит на страницу глазами, кликает, печатает, перемещается. То, что раньше требовало дни программирования, теперь делается за вечер.

Зачем именно Playwright

Playwright — это headless browser от Microsoft (форк Chromium с API сверху). Альтернативы: Puppeteer (Google, очень похож), Selenium (древний, медленный). Playwright выигрывает в трёх вещах: (1) auto-wait — не нужно вручную ждать загрузки элементов; (2) нативная поддержка Chrome, Firefox и Safari через одно API; (3) встроенный screenshot, video, network mocking. Для агентов это золото: можно дать Claude скриншот страницы, попросить «куда кликнуть» и получить координаты или селектор.

Архитектура браузерного агента

Простой подход: даёшь Claude несколько инструментов — open(url), screenshot(), click(selector), type(selector, text), get_text(selector), wait_for(selector). На каждом шаге Claude получает скриншот и/или DOM, решает что делать, вызывает один из инструментов. Цикл повторяется пока задача не решена. Чтобы не отправлять весь HTML (огромный) — отдаёшь либо скриншот (vision), либо текстовое представление страницы (упрощённый DOM с интерактивными элементами).

DOM или screenshot — что отдавать модели

Два пути. (1) Текстовый DOM — парсишь страницу в плоский текст с маркерами кликабельных элементов: "[1] Login button, [2] Email input, [3] Password input". Модель работает с номерами. Дешевле, быстрее, но теряется визуальная инфа. (2) Screenshot + grounding — отправляешь PNG страницы, модель отвечает «кликни на кнопку Login в правом верхнем углу», ты ищешь ближайший button по тексту. Дороже но универсальнее. На практике — гибрид: текстовое представление + screenshot для визуальных задач.

Главные грабли

Что валит браузерных агентов чаще всего: (1) Не дождался загрузки — странные ошибки. Решение: использовать page.waitForLoadState и page.waitForSelector. (2) Динамические селекторы — сайт меняет class="x_a8sd" на каждом релизе. Решение: цепляться за data-testid, role, или text. (3) Pop-ups и cookie-баннеры — закрывают нужные элементы. Решение: на старте сессии всегда закрывать известные баннеры. (4) Anti-bot защита — Cloudflare палит headless. Решение: playwright-extra со stealth-плагином или playwright-stealth. (5) Бесконечная прокрутка — модель не знает где остановиться. Решение: явный max_scroll параметр.

Безопасность — обязательная часть

Браузерный агент == код может попасть на ЛЮБОЙ сайт. Опасности: переход по фишинг-ссылкам, ввод твоих кредов на похожем сайте, downloading malware, скачивание персональных данных третьих лиц. Минимум: (1) Whitelist доменов в инструменте open — без него отказ. (2) Никогда не давать инструменту type значения секретов — клади их в env и подставляй из инструмента fill_login(name) который тянет из vault. (3) Запускай браузер в изолированной директории (separate browser profile), не в основной. (4) Логируй ВСЕ действия для аудита.

примерtypescript
import { chromium, Page } from 'playwright';
import Anthropic from '@anthropic-ai/sdk';

const client = new Anthropic();
const ALLOWED_DOMAINS = ['example.com', 'wikipedia.org'];

let page: Page | null = null;

async function openUrl(url: string): Promise<string> {
  const host = new URL(url).hostname;
  if (!ALLOWED_DOMAINS.some(d => host.endsWith(d))) {
    return `Error: домен ${host} не в whitelist`;
  }
  if (!page) {
    const browser = await chromium.launch({ headless: true });
    page = await browser.newPage();
  }
  await page.goto(url, { waitUntil: 'domcontentloaded' });
  return `Открыта страница ${url}, заголовок: ${await page.title()}`;
}

async function getText(selector: string): Promise<string> {
  if (!page) return 'Error: страница не открыта';
  try {
    return (await page.locator(selector).first().textContent()) ?? '';
  } catch (e) {
    return `Error: ${(e as Error).message}`;
  }
}

const tools = [
  {
    name: 'open_url',
    description: 'Открывает URL в браузере. Whitelist доменов обязателен.',
    input_schema: {
      type: 'object',
      properties: { url: { type: 'string' } },
      required: ['url'],
    },
  },
  {
    name: 'get_text',
    description: 'Возвращает текст элемента по CSS-селектору. Используй после open_url.',
    input_schema: {
      type: 'object',
      properties: { selector: { type: 'string' } },
      required: ['selector'],
    },
  },
];

// Дальше стандартный agent loop из урока «Цикл агента»
// На каждом step вызываем нужный tool, передаём результат обратно в Claude.

Минимальный браузерный агент: открыть сайт, найти заголовок, вернуть текст

главное
  • 01Playwright = headless-браузер с auto-wait и screenshot. Связка с Claude закрывает 90% задач парсинга и автоматизации.
  • 02Отдавай модели либо упрощённый DOM с номерами кликабельных элементов, либо screenshot — выбирай по задаче.
  • 03data-testid > class > xpath. Никогда не цепляйся за хешированные классы.
  • 04Whitelist доменов и vault для секретов — must-have. Без них ты дал ИИ твою кредитку.
  • 05Anti-bot защита (Cloudflare) — лечится stealth-плагинами, но на серьёзных сайтах не работает совсем. Не строй бизнес на парсинге защищённых сервисов.
проверь себя
01Что лучше всего в качестве селектора для браузерного агента?
02Почему whitelist доменов обязателен для браузерного агента?
03Как лучше обработать секреты (логин/пароль) в браузерном агенте?
следующий урок: Агент по расписанию — самообновляющийся дайджест