Node.js парсер отзывов: как собирать данные с 20 площадок
Коротко: Node.js парсер отзывов может собирать до 50 000 отзывов в час с 20+ площадок одновременно. Связка Puppeteer + Cheerio + Proxy-rotation решает 90% задач по сбору отзывов, а правильная архитектура ETL-пайплайна обеспечивает стабильную работу 24/7 с нагрузкой до 100 запросов в секунду.
Содержание
- Почему именно Node.js для парсинга отзывов?
- Как спроектировать архитектуру парсера
- Какие площадки парсить и как обходить защиту
- Пошаговая реализация базового парсера
- Как оптимизировать скорость и надёжность
- ETL-пайплайн и мониторинг процессов
- Правовые аспекты и лимиты
- Частые вопросы
Почему именно Node.js для парсинга отзывов?
Когда мы в DS495 выбирали стек для парсера отзывов, рассматривали Python с Scrapy, но в итоге остановились на Node.js. Причина простая — асинхронность из коробки. Парсинг отзывов — это массово параллельная задача. Нужно одновременно обрабатывать сотни страниц, ждать загрузки контента, работать с прокси. Node.js справляется с этим идеально благодаря event loop.| Параметр | Node.js | Python | Преимущество |
|---|---|---|---|
| Параллельные запросы | До 1000 без блокировки | Ограничено GIL | Node.js |
| Потребление памяти | ~50MB на 100 воркеров | ~200MB на 100 воркеров | Node.js |
| Время старта | 500ms | 2-3 секунды | Node.js |
| Экосистема для веба | Puppeteer, Cheerio | Scrapy, BeautifulSoup | Примерно равно |
- Puppeteer — для JavaScript-heavy сайтов (Wildberries, OZON)
- Cheerio — для статического контента (старые версии Яндекс.Маркета)
- Axios — HTTP-клиент с поддержкой прокси
- Playwright — альтернатива Puppeteer с лучшей производительностью
Как спроектировать архитектуру парсера
Парсер отзывов — это не просто скрипт, который ходит по страницам. Это полноценная система сбора данных с очередями, кэшированием и обработкой ошибок. Мы строим архитектуру по принципу микросервисов:- URL Generator — генерирует ссылки для парсинга
- Fetcher Pool — пул воркеров для загрузки страниц
- Parser Engine — извлекает данные из HTML
- Data Validator — проверяет качество данных
- Storage Writer — сохраняет в БД или файлы
В одном проекте мы парсили отзывы для сети магазинов электроники. За месяц собрали 2.3 млн отзывов с 15 площадок. Система работала 24/7 без сбоев благодаря правильной архитектуре.Основные компоненты ETL-пайплайна: ```javascript // Базовая структура парсера class ReviewParser { constructor(config) { this.platforms = config.platforms; this.workers = config.workers || 10; this.retries = config.retries || 3; this.delay = config.delay || 1000; } async start() { const queue = new TaskQueue(); const workers = Array(this.workers).fill().map(() => new Worker(queue, this.parseReviews.bind(this)) ); await Promise.all(workers.map(w => w.start())); } } ``` Для мониторинга используем Redis как очередь задач и хранилище метрик. MongoDB или PostgreSQL для финальных данных — зависит от объёмов и структуры.
Какие площадки парсить и как обходить защиту
20 площадок — это серьёзная нагрузка. У каждой свои особенности защиты от ботов. Мы разделили их на три группы по сложности парсинга:| Сложность | Площадки | Защита | Решение |
|---|---|---|---|
| Низкая | Avito, Яндекс.Маркет (старая версия) | Rate limiting | Прокси + задержки |
| Средняя | Wildberries, OZON, AliExpress | JavaScript + капча | Puppeteer + rotating proxies |
| Высокая | Amazon, Google Reviews | Cloudflare + bot detection | Residential proxy + fingerprint spoofing |
Нужна помощь с этой задачей? Команда DS495 решит её под ключ. Обсудить проект →Основные методы обхода защиты:
- Rotation прокси — меняем IP каждые 10-50 запросов
- User-Agent spoofing — имитируем разные браузеры
- Captcha solving — интеграция с 2captcha или AntiCaptcha
- Headless detection — настройка Puppeteer под реальный браузер
- Cookie management — сохранение сессий между запросами
Пошаговая реализация базового парсера
Покажу, как создать рабочий парсер отзывов с нуля. Начнём с простого примера для одной площадки, потом масштабируем. **Шаг 1: Настройка окружения** ```bash npm init -y npm install puppeteer cheerio axios winston redis ioredis npm install --save-dev nodemon ``` **Шаг 2: Создание базового класса парсера** ```javascript const puppeteer = require('puppeteer'); const axios = require('axios'); const cheerio = require('cheerio'); class ReviewScraper { constructor(options = {}) { this.browser = null; this.proxies = options.proxies || []; this.delay = options.delay || 2000; this.retries = options.retries || 3; } async init() { this.browser = await puppeteer.launch({ headless: true, args: [ '--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage' ] }); } } ``` **Шаг 3: Реализация парсинга для конкретной площадки** ```javascript async parseWildberries(productId) { const url = `https://www.wildberries.ru/catalog/${productId}/detail.aspx`; const page = await this.browser.newPage(); try { await page.goto(url, { waitUntil: 'networkidle0' }); // Ждём загрузки отзывов await page.waitForSelector('.review-item', { timeout: 10000 }); const reviews = await page.evaluate(() => { const reviewElements = document.querySelectorAll('.review-item'); return Array.from(reviewElements).map(el => ({ author: el.querySelector('.review-author')?.textContent?.trim(), rating: el.querySelector('.review-rating')?.getAttribute('data-rating'), text: el.querySelector('.review-text')?.textContent?.trim(), date: el.querySelector('.review-date')?.textContent?.trim() })); }); return reviews; } finally { await page.close(); } } ``` **Шаг 4: Добавление обработки ошибок и ретраев** ```javascript async scrapeWithRetry(scrapeFunction, ...args) { for (let attempt = 1; attempt <= this.retries; attempt++) { try { const result = await scrapeFunction.apply(this, args); return result; } catch (error) { console.log(`Attempt ${attempt} failed:`, error.message); if (attempt === this.retries) { throw error; } // Экспоненциальная задержка await this.sleep(this.delay * Math.pow(2, attempt - 1)); } } } ``` **Шаг 5: Интеграция с очередью задач** ```javascript const Redis = require('ioredis'); class TaskQueue { constructor() { this.redis = new Redis(process.env.REDIS_URL); } async addTask(platform, productId) { const task = { platform, productId, timestamp: Date.now() }; await this.redis.lpush('scraping_queue', JSON.stringify(task)); } async getTask() { const task = await this.redis.brpop('scraping_queue', 10); return task ? JSON.parse(task[1]) : null; } } ``` **Шаг 6: Создание воркера для обработки задач** ```javascript class Worker { constructor(scraper, queue) { this.scraper = scraper; this.queue = queue; this.isRunning = false; } async start() { this.isRunning = true; while (this.isRunning) { try { const task = await this.queue.getTask(); if (!task) continue; const reviews = await this.processTask(task); await this.saveReviews(reviews, task); console.log(`Processed ${task.platform}:${task.productId}`); } catch (error) { console.error('Worker error:', error); } } } } ```Как оптимизировать скорость и надёжность
Когда парсер работает 24/7 и обрабатывает тысячи страниц, каждая миллисекунда важна. Мы оптимизируем по трём направлениям: скорость, надёжность и потребление ресурсов. **Оптимизация скорости:** Основная проблема — медленная загрузка страниц. Puppeteer по умолчанию ждёт все ресурсы, включая картинки и аналитику. Это можно отключить: ```javascript await page.setRequestInterception(true); page.on('request', (req) => { const resourceType = req.resourceType(); if (['image', 'stylesheet', 'font'].includes(resourceType)) { req.abort(); } else { req.continue(); } }); ``` Результат: скорость парсинга выросла с 300 до 1200 страниц в час. **Connection pooling для HTTP-запросов:** ```javascript const axios = require('axios'); const Agent = require('agentkeepalive'); const httpAgent = new Agent({ maxSockets: 100, maxFreeSockets: 10, timeout: 60000, freeSocketTimeout: 30000 }); const client = axios.create({ httpAgent, timeout: 30000 }); ``` **Кэширование результатов:** Многие товары имеют одинаковые отзывы на разных страницах. Мы кэшируем уже обработанные отзывы по хэшу от текста: ```javascript const crypto = require('crypto'); function getReviewHash(review) { return crypto .createHash('md5') .update(`${review.text}${review.author}`) .digest('hex'); } // Проверка в кэше перед сохранением if (await redis.exists(`review:${hash}`)) { return; // Отзыв уже есть } ``` Это сокращает объём сохраняемых данных на 40-60%.ETL-пайплайн и мониторинг процессов
ETL (Extract, Transform, Load) — основа надёжного парсера. Мы разделили процесс на независимые этапы, каждый со своими метриками и мониторингом. **Extract (Извлечение):** - Загрузка HTML/JSON с целевых площадок - Обработка ошибок сети и таймаутов - Ротация прокси и User-Agent'ов - Метрика: количество успешных запросов в минуту **Transform (Трансформация):** - Парсинг HTML и извлечение структурированных данных - Нормализация текста (удаление лишних пробелов, emoji) - Определение языка и тональности отзывов - Метрика: процент корректно распарсенных страниц **Load (Загрузка):** - Валидация данных перед сохранением - Дедупликация по хэшам - Сохранение в БД с правильной индексацией - Метрика: скорость записи в секунду- Prometheus + Grafana — для системных метрик и дашбордов
- Winston — структурированное логирование
- PM2 — управление процессами и автоперезапуск
- Redis — очередь задач и кэш промежуточных результатов
- Падение скорости парсинга ниже 500 страниц/час
- Процент ошибок выше 15%
- Недоступность более 3 площадок одновременно
- Переполнение очереди задач (>10000 pending)
Правовые аспекты и лимиты
Парсинг отзывов находится в серой зоне. Формально это публичная информация, но сайты могут ограничивать автоматический доступ через robots.txt и пользовательские соглашения. **Основные принципы безопасного парсинга:**- Соблюдение robots.txt — хотя бы формально
- Разумные лимиты — не более 1-2 запросов в секунду на площадку
- Использование данных только для анализа — не для перепубликации
- Обезличивание персональных данных — хэширование имён авторов
| Площадка | Запросов в минуту | Максимальный объём | Ограничения |
|---|---|---|---|
| Wildberries | 30 | 10 000 отзывов/день | Блокировка по IP |
| OZON | 20 | 5 000 отзывов/день | Капча после 100 запросов |
| Яндекс.Маркет | 60 | 50 000 отзывов/день | Rate limiting |
| Amazon | 10 | 1 000 отзывов/день | Жёсткая защита |
В одном проекте нам нужно было собрать отзывы о конкурентах для сети спортивных магазинов. Мы ограничились 5000 отзывов в день на площадку и растянули сбор на 2 месяца. Зато ни разу не получили блокировку.**Что точно нельзя делать:**
- Парсить персональные данные пользователей (email, телефоны)
- Перепубликовывать отзывы без согласия авторов
- Создавать высокую нагрузку на серверы (>100 RPS)
- Игнорировать официальные API, если они есть
Частые вопросы
В: Сколько времени занимает разработка парсера для 20 площадок?
О: От 2 до 6 месяцев в зависимости от сложности площадок. Базовый парсер для 5-7 простых сайтов можно сделать за месяц, но добавление защищённых площадок (Amazon, Google) может занять ещё 3-4 месяца.
В: Какую производительность можно ожидать от Node.js парсера?
О: На одном сервере (8 CPU, 16GB RAM) мы получаем 2000-5000 страниц в час. С кластером из 5 серверов и правильной балансировкой нагрузки — до 50 000 отзывов в час.
В: Нужно ли покупать дорогие прокси для парсинга?
О: Зависит от площадок. Для российских сайтов (Wildberries, OZON) достаточно дата-центровых прокси за $50-100/месяц. Для Amazon и Google нужны residential прокси от $200/месяц.
В: Как обойти Cloudflare защиту?
О: Используйте Playwright вместо Puppeteer, настройте правильные fingerprints, работайте через residential прокси и добавьте случайные задержки. В 70% случаев это помогает.
В: Можно ли парсить отзывы легально?
О: Отзывы — публичная информация, но парсинг может нарушать пользовательское соглашение сайта. Используйте данные только для анализа, соблюдайте разумные лимиты и не перепубликовывайте контент.
В: Какой объём данных можно собрать за месяц?
О: При соблюдении лимитов — 500 000 - 1 500 000 отзывов с 20 площадок. Больше не рекомендуем из-за риска блокировок.
В: Стоит ли использовать готовые решения вместо самописного парсера?
О: Готовые API (ReviewAPI, ScraperAPI) стоят $500-2000/месяц и покрывают 5-10 популярных площадок. Самописный парсер дешевле при больших объёмах и даёт полный контроль.
Читайте также
- RAG-система для e-commerce: как настроить ИИ-ассистента с GPT-4 и Claude для персонализации товарных рекомендаций и увеличить средний чек на 85% за 60 дней
- Node.js vs Python для бэкенда в 2026 году: что выбрать и как это влияет на стоимость разработки
- React или Next.js: что выбрать для сайта в 2026 году и как это влияет на бюджет
Нужна помощь с этим? Обсудить проект с DS495 →