Автоматизация парсинга динамических сайтов: Playwright + Bun + Zod в TypeScript
-

Динамические сайты с кучей JavaScript - это головная боль для парсеров. Обычный fetch или axios не вытащат контент, который грузится асинхронно. Здесь на помощь приходит Playwright - он запускает реальный браузер и эмулирует действия юзера.
Соберем full-stack скрипт на Bun для скорости, TypeScript для типизации и Zod для валидации данных. Это сэкономит часы на ручном сборе данных, идеально для бизнеса: цены конкурентов, отзывы или новости. Получится быстрый парсер, который легко деплоить и масштабировать.
Почему Playwright рвет шаблон для динамики
Современные сайты вроде Instagram или Twitch пихают весь сок в JS: ленты скроллятся бесконечно, фильтры подгружаются AJAX-ом. Простой HTTP-запрос вернет голый HTML без нужного. Playwright решает это headless-браузером - Chromium, Firefox или Webkit на выбор.
Он не просто грузит страницу, а ждёт, пока JS отработает, кликает кнопки, скроллит и даже меняет user-agent. Представь: парсим каталог товаров с пагинацией - клик, ввод в поиск, скролл до конца. Без багов с теневым DOM или iframe-ами. А с TypeScript код становится предсказуемым, без сюрпризов в runtime.
- Headless-режим: браузер не виден, жрёт меньше ресурсов, идеально для сервака.
- Эмуляция действий:
page.click(),page.fill()- как настоящий юзер, обходит антиботы. - Скриншоты и видео:
page.screenshot()для дебага, если что-то сломалось.
Фича Playwright Puppeteer Selenium Браузеры Chromium, Firefox, Webkit Только Chromium Все, но медленнее Скорость Высокая, async Хорошая Средняя TypeScript Нативная поддержка Через @types Сложнее Нюанс: всегда ставь таймауты -
waitForSelector()с timeout: 10000, чтоб не висеть вечно.Bun - турбо-ускоритель для Node-скриптов
Bun - это не просто runtime, а замена Node.js с JavaScriptCore. Установка пакетов в 10x быстрее, запуск скрипта - молния. Для парсера на сервере это критично: парсим 1000 страниц - и не ждём минуты.
В связке с Playwright Bun тянет всё:
bun install playwright, и готово. Нет package-lock.json-войн - bun.lock решает конфликты. Плюс встроенный bundler и test runner. Наткнулся на релиз Bun 1.2 - S3-пакеты в 5 раз шустрее, SQL для Postgres. Идеально для пет-проекта, который вырастет в сервис.- Установка:
bun init,bun add playwright zod,bun add -d @types/node- секунды. - Запуск:
bun run parse.ts- без ts-node, нативно. - Hot reload: меняешь код - перезапуск мгновенный.
Сравнение runtime Bun Node.js Deno Установка deps 10x быстрее Стандарт Хорош, но меньше экосистемы Память Меньше Больше Сопоставимо TypeScript Нативно Через tsx Нативно Лайфхак: используй
Bun.file()для чтения JSON-ов локально, быстрее fs.readFile.Zod - типы и валидация в одном флаконе
Парсинг без схем - лотерея: цена пришла строкой, id - числом. Zod рисует схемы, валидирует и выводит TypeScript-типы автоматически.
z.object({ name: z.string(), price: z.number() })- и тип готов:z.infer<typeof schema>.В нашем скрипте Zod проверит данные с Playwright: цена - число, название - строка до 100 символов. Ошибка?
parse()кинет ZodError с деталями. Никаких any в типах, автокомплит в VS Code летает. Плюс regex для UUID или имейлов.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<typeof ProductSchema>;- Преобразования:
.transform()- строка в число, дата в Date. - Опционалки:
z.number().optional()- если цена отсутствует. - Массивы:
z.array(ProductSchema)для списка товаров.
Важно: всегда
.safeParse()в проде, чтоб не крашить скрипт на кривых данных.Полный DIY-скрипт: от запуска до сохранения
Собираем всё вместе. Скрипт парсит каталог товаров: открывает страницу, применяет фильтры, скроллит, экстрактит данные Zod’ом. Full-stack - frontend эмуляция + backend-логика в одном файле. Запускай на VPS через pm2 или systemd.
Код готов к копипасту. Настраивай селекторы под свой сайт - используй Playwright Inspector (
npx playwright codegen). Сохраняем в JSON или SQLite через Bun.sql.import { chromium } from 'playwright'; import { z } from 'zod'; const Product = z.object({ name: z.string(), price: z.number(), }); type Product = z.infer<typeof Product>; 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(() => window.scrollTo(0, document.body.scrollHeight)); const data = await page.evaluate(() => { return Array.from(document.querySelectorAll('[data-product]')).map(el => ({ 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));- Расширение: добавь прокси
page.route()для ротации IP. - Параллель:
Promise.all()для нескольких страниц. - Логи:
test.step()из Playwright для отладки.
Шаг Команда Установка bun add playwright zodЗапуск bun run parse.tsДеплой bun pm2 start parse.tsМасштаб за кадром: от скрипта к сервису
Этот стек тянет от пет-проекта до production: добавь API на Elysia (Bun-фреймворк), кэш в Redis, оркестрацию через Docker. Осталось интегрировать ИИ - отправь данные в Grok API для анализа цен. Или cron для ежедневного парсинга.
Динамика эволюционирует - жди фич вроде встроенного AI в Playwright. Подумай о stealth-плагинах против Cloudflare. Код живой, апгрейдь под новые релизы Bun и TypeScript.
Здравствуйте! Похоже, вас заинтересовала эта беседа, но у вас ещё нет аккаунта.
Надоело каждый раз пролистывать одни и те же посты? Зарегистрировав аккаунт, вы всегда будете возвращаться на ту же страницу, где были раньше, и сможете выбирать, получать ли уведомления о новых ответах (по электронной почте или в виде push-уведомлений). Вы также сможете сохранять закладки и ставить лайки постам, чтобы выразить свою благодарность другим участникам сообщества.
С вашими комментариями этот пост мог бы стать ещё лучше 💗
Зарегистрироваться Войти© 2024 - 2026 ExLends, Inc. Все права защищены.