<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Автоматизация парсинга динамических сайтов: Playwright + Bun + Zod в TypeScript]]></title><description><![CDATA[<p dir="auto"><img src="/assets/uploads/files/d5/f4/56/1773937730201-generated_1773937693496-resized.webp" alt="Обложка: Как автоматизировать парсинг динамических сайтов с Playwright, Bun и Zod в TypeScript: DIY-скрипт для full-stack автоматизации" class=" img-fluid img-markdown" /></p>
<p dir="auto">Динамические сайты с кучей JavaScript - это головная боль для парсеров. Обычный fetch или axios не вытащат контент, который грузится асинхронно. Здесь на помощь приходит <strong>Playwright</strong> - он запускает реальный браузер и эмулирует действия юзера.</p>
<p dir="auto">Соберем full-stack скрипт на <strong>Bun</strong> для скорости, <strong>TypeScript</strong> для типизации и <strong>Zod</strong> для валидации данных. Это сэкономит часы на ручном сборе данных, идеально для бизнеса: цены конкурентов, отзывы или новости. Получится быстрый парсер, который легко деплоить и масштабировать.</p>
<h2>Почему Playwright рвет шаблон для динамики</h2>
<p dir="auto">Современные сайты вроде Instagram или Twitch пихают весь сок в JS: ленты скроллятся бесконечно, фильтры подгружаются AJAX-ом. Простой HTTP-запрос вернет голый HTML без нужного. <strong>Playwright</strong> решает это headless-браузером - Chromium, Firefox или Webkit на выбор.</p>
<p dir="auto">Он не просто грузит страницу, а ждёт, пока JS отработает, кликает кнопки, скроллит и даже меняет user-agent. Представь: парсим каталог товаров с пагинацией - клик, ввод в поиск, скролл до конца. Без багов с теневым DOM или iframe-ами. А с <strong>TypeScript</strong> код становится предсказуемым, без сюрпризов в runtime.</p>
<ul>
<li><strong>Headless-режим</strong>: браузер не виден, жрёт меньше ресурсов, идеально для сервака.</li>
<li><strong>Эмуляция действий</strong>: <code>page.click()</code>, <code>page.fill()</code> - как настоящий юзер, обходит антиботы.</li>
<li><strong>Скриншоты и видео</strong>: <code>page.screenshot()</code> для дебага, если что-то сломалось.</li>
</ul>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Фича</th>
<th>Playwright</th>
<th>Puppeteer</th>
<th>Selenium</th>
</tr>
</thead>
<tbody>
<tr>
<td>Браузеры</td>
<td>Chromium, Firefox, Webkit</td>
<td>Только Chromium</td>
<td>Все, но медленнее</td>
</tr>
<tr>
<td>Скорость</td>
<td>Высокая, async</td>
<td>Хорошая</td>
<td>Средняя</td>
</tr>
<tr>
<td>TypeScript</td>
<td>Нативная поддержка</td>
<td>Через @types</td>
<td>Сложнее</td>
</tr>
</tbody>
</table>
<p dir="auto"><em>Нюанс</em>: всегда ставь таймауты - <code>waitForSelector()</code> с timeout: 10000, чтоб не висеть вечно.</p>
<h2>Bun - турбо-ускоритель для Node-скриптов</h2>
<p dir="auto"><strong>Bun</strong> - это не просто runtime, а замена Node.js с JavaScriptCore. Установка пакетов в 10x быстрее, запуск скрипта - молния. Для парсера на сервере это критично: парсим 1000 страниц - и не ждём минуты.</p>
<p dir="auto">В связке с Playwright Bun тянет всё: <code>bun install playwright</code>, и готово. Нет package-lock.json-войн - bun.lock решает конфликты. Плюс встроенный bundler и test runner. Наткнулся на релиз Bun 1.2 - S3-пакеты в 5 раз шустрее, SQL для Postgres. Идеально для пет-проекта, который вырастет в сервис.</p>
<ul>
<li><strong>Установка</strong>: <code>bun init</code>, <code>bun add playwright zod</code>, <code>bun add -d @types/node</code> - секунды.</li>
<li><strong>Запуск</strong>: <code>bun run parse.ts</code> - без ts-node, нативно.</li>
<li><strong>Hot reload</strong>: меняешь код - перезапуск мгновенный.</li>
</ul>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Сравнение runtime</th>
<th>Bun</th>
<th>Node.js</th>
<th>Deno</th>
</tr>
</thead>
<tbody>
<tr>
<td>Установка deps</td>
<td>10x быстрее</td>
<td>Стандарт</td>
<td>Хорош, но меньше экосистемы</td>
</tr>
<tr>
<td>Память</td>
<td>Меньше</td>
<td>Больше</td>
<td>Сопоставимо</td>
</tr>
<tr>
<td>TypeScript</td>
<td>Нативно</td>
<td>Через tsx</td>
<td>Нативно</td>
</tr>
</tbody>
</table>
<p dir="auto"><em>Лайфхак</em>: используй <code>Bun.file()</code> для чтения JSON-ов локально, быстрее fs.readFile.</p>
<h2>Zod - типы и валидация в одном флаконе</h2>
<p dir="auto">Парсинг без схем - лотерея: цена пришла строкой, id - числом. <strong>Zod</strong> рисует схемы, валидирует и выводит TypeScript-типы автоматически. <code>z.object({ name: z.string(), price: z.number() })</code> - и тип готов: <code>z.infer&lt;typeof schema&gt;</code>.</p>
<p dir="auto">В нашем скрипте Zod проверит данные с Playwright: цена - число, название - строка до 100 символов. Ошибка? <code>parse()</code> кинет ZodError с деталями. Никаких any в типах, автокомплит в VS Code летает. Плюс regex для UUID или имейлов.</p>
<pre><code class="language-typescript">import { z } from 'zod';

const ProductSchema = z.object({
  name: z.string().max(100),
  price: z.string().regex(/\d+/).transform(Number),
  id: z.string().uuid(),
});

type Product = z.infer&lt;typeof ProductSchema&gt;;
</code></pre>
<ul>
<li><strong>Преобразования</strong>: <code>.transform()</code> - строка в число, дата в Date.</li>
<li><strong>Опционалки</strong>: <code>z.number().optional()</code> - если цена отсутствует.</li>
<li><strong>Массивы</strong>: <code>z.array(ProductSchema)</code> для списка товаров.</li>
</ul>
<p dir="auto"><em>Важно</em>: всегда <code>.safeParse()</code> в проде, чтоб не крашить скрипт на кривых данных.</p>
<h2>Полный DIY-скрипт: от запуска до сохранения</h2>
<p dir="auto">Собираем всё вместе. Скрипт парсит каталог товаров: открывает страницу, применяет фильтры, скроллит, экстрактит данные Zod’ом. <strong>Full-stack</strong> - frontend эмуляция + backend-логика в одном файле. Запускай на VPS через pm2 или systemd.</p>
<p dir="auto">Код готов к копипасту. Настраивай селекторы под свой сайт - используй Playwright Inspector (<code>npx playwright codegen</code>). Сохраняем в JSON или SQLite через Bun.sql.</p>
<pre><code class="language-typescript">import { chromium } from 'playwright';
import { z } from 'zod';

const Product = z.object({
  name: z.string(),
  price: z.number(),
});

type Product = z.infer&lt;typeof Product&gt;;

async function parseSite(url: string) {
  const browser = await chromium.launch({ headless: true });
  const page = await browser.newPage();
  await page.goto(url);

  // Ждём загрузки
  await page.waitForSelector('[data-product]');

  // Скролл для динамики
  await page.evaluate(() =&gt; window.scrollTo(0, document.body.scrollHeight));

  const data = await page.evaluate(() =&gt; {
    return Array.from(document.querySelectorAll('[data-product]')).map(el =&gt; ({
      name: el.querySelector('.name')?.textContent || '',
      price: parseFloat(el.querySelector('.price')?.textContent || '0'),
    }));
  });

  const products = z.array(Product).parse(data);
  await browser.close();
  return products;
}

// Запуск
const products = await parseSite('https://example.com/shop');
console.log(products);
Bun.write(Bun.file('products.json'), JSON.stringify(products));
</code></pre>
<ul>
<li><strong>Расширение</strong>: добавь прокси <code>page.route()</code> для ротации IP.</li>
<li><strong>Параллель</strong>: <code>Promise.all()</code> для нескольких страниц.</li>
<li><strong>Логи</strong>: <code>test.step()</code> из Playwright для отладки.</li>
</ul>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Шаг</th>
<th>Команда</th>
</tr>
</thead>
<tbody>
<tr>
<td>Установка</td>
<td><code>bun add playwright zod</code></td>
</tr>
<tr>
<td>Запуск</td>
<td><code>bun run parse.ts</code></td>
</tr>
<tr>
<td>Деплой</td>
<td><code>bun pm2 start parse.ts</code></td>
</tr>
</tbody>
</table>
<h2>Масштаб за кадром: от скрипта к сервису</h2>
<p dir="auto">Этот стек тянет от пет-проекта до production: добавь API на Elysia (Bun-фреймворк), кэш в Redis, оркестрацию через Docker. Осталось интегрировать ИИ - отправь данные в Grok API для анализа цен. Или cron для ежедневного парсинга.</p>
<p dir="auto">Динамика эволюционирует - жди фич вроде встроенного AI в Playwright. Подумай о stealth-плагинах против Cloudflare. Код живой, апгрейдь под новые релизы Bun и TypeScript.</p>
]]></description><link>https://forum.exlends.ru/topic/1772/avtomatizaciya-parsinga-dinamicheskih-sajtov-playwright-bun-zod-v-typescript</link><generator>RSS for Node</generator><lastBuildDate>Sat, 17 Oct 2026 03:07:16 GMT</lastBuildDate><atom:link href="https://forum.exlends.ru/topic/1772.rss" rel="self" type="application/rss+xml"/><pubDate>Thu, 19 Mar 2026 16:28:50 GMT</pubDate><ttl>60</ttl></channel></rss>