Параллельный скрейпинг

Параллельный скрейпинг с Puppeteer

Скрейпинг — это процесс извлечения данных с веб-страниц с использованием автоматических инструментов. Puppeteer — это библиотека для Node.js, которая предоставляет API для управления браузером Chromium или Chrome через DevTools протокол. В этой главе рассмотрим, как использовать Puppeteer для выполнения параллельного скрейпинга, что позволяет ускорить процесс извлечения данных с нескольких страниц одновременно.

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

Основные преимущества параллельного скрейпинга:

  • Ускорение обработки больших объемов данных.
  • Эффективное использование ресурсов.
  • Снижение времени ожидания между запросами.

Как организовать параллельный скрейпинг?

Puppeteer позволяет управлять несколькими страницами или браузерными сессиями одновременно. Это можно сделать с помощью асинхронных функций и параллельных задач.

Структура параллельного скрейпинга

Для реализации параллельного скрейпинга в Puppeteer можно использовать несколько подходов, среди которых:

  1. Многократное использование одной браузерной сессии. В этом случае все страницы открываются в одном браузере, но в разных вкладках.
  2. Множественные браузерные сессии. В этом случае каждый скрейпинг происходит в отдельном экземпляре браузера.

В большинстве случаев предпочтительнее использовать первый вариант, так как он экономит ресурсы, не открывая несколько экземпляров браузера, что может быть довольно ресурсоемким.

Пример параллельного скрейпинга с использованием одной браузерной сессии

Для этого можно создать несколько вкладок в одном экземпляре браузера и выполнять параллельные задачи для каждой страницы.

const puppeteer = require(&

async function scrapePage(url) {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto(url);
  const data = await page.evaluate(() => {
    return document.title; // Пример: получение заголовка страницы
  });
  await browser.close();
  return data;
}

async function scrapeParallel(urls) {
  const browser = await puppeteer.launch();
  const promises = urls.map(async (url) => {
    const page = await browser.newPage();
    await page.goto(url);
    const data = await page.evaluate(() => {
      return document.title; // Пример: получение заголовка страницы
    });
    await page.close();
    return data;
  });

  const results = await Promise.all(promises);
  await browser.close();
  return results;
}

const urls = ['https://example.com', 'https://example2.com', 'https://example3.com'];
scrapeParallel(urls).then((results) => {
  console.log(results); // Вывод заголовков всех страниц
});

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

Множественные браузерные сессии

Если нужно запускать несколько браузеров (например, для более сильной изоляции задач или при большом количестве одновременных запросов), можно использовать несколько экземпляров Puppeteer.

const puppeteer = require('puppeteer');

async function scrapeParallelWithMultipleBrowsers(urls) {
  const browserPromises = urls.map(async (url) => {
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    await page.goto(url);
    const data = await page.evaluate(() => {
      return document.title;
    });
    await browser.close();
    return data;
  });

  const results = await Promise.all(browserPromises);
  return results;
}

const urls = ['https://example.com', 'https://example2.com', 'https://example3.com'];
scrapeParallelWithMultipleBrowsers(urls).then((results) => {
  console.log(results);
});

Каждый браузер запускается в отдельном процессе, что позволяет добиться большей изоляции и параллельности, но это потребует больше системных ресурсов.

Ограничения и учёт производительности

Хотя параллельный скрейпинг значительно ускоряет процесс сбора данных, следует учитывать некоторые моменты, связанные с производительностью:

  • Ресурсоёмкость: каждый экземпляр браузера или вкладка требует памяти и CPU. При большом числе параллельных запросов можно столкнуться с проблемами из-за ограничений памяти.
  • Политики сайтов: многие сайты ограничивают количество запросов от одного IP-адреса. При слишком частых запросах можно столкнуться с блокировками.
  • Ограничения на количество параллельных сессий: рекомендуется не запускать слишком большое количество сессий или вкладок одновременно. Лучше использовать стратегию с ограничением параллельных задач и управлением потоком.

Управление потоками запросов

Для более точного контроля над количеством одновременно выполняемых задач можно использовать специальные библиотеки для управления параллельными задачами, такие как Promise.allSettled, async/await с лимитированием параллельных запросов или библиотеки, такие как p-limit или bluebird.

Пример с использованием p-limit для ограничения параллельных запросов:

const puppeteer = require('puppeteer');
const pLimit = require('p-limit');

const limit = pLimit(5); // Ограничение до 5 параллельных задач

async function scrapeParallelWithLimit(urls) {
  const browser = await puppeteer.launch();
  const promises = urls.map((url) =>
    limit(async () => {
      const page = await browser.newPage();
      await page.goto(url);
      const data = await page.evaluate(() => {
        return document.title;
      });
      await page.close();
      return data;
    })
  );

  const results = await Promise.all(promises);
  await browser.close();
  return results;
}

const urls = ['https://example.com', 'https://example2.com', 'https://example3.com'];
scrapeParallelWithLimit(urls).then((results) => {
  console.log(results);
});

Этот пример ограничивает количество параллельных запросов до 5 одновременно выполняющихся задач, что позволяет избежать чрезмерной нагрузки на систему.

Работа с капчей

При масштабировании скрейпинга, особенно при большом количестве параллельных запросов, существует вероятность, что сайт может применить защиту от ботов, такую как капча. Для обхода этого можно использовать различные подходы:

  • Прокси-серверы: использование прокси-серверов или ротации IP-адресов для обхода блокировок.
  • Решение капчи: в некоторых случаях возможно автоматическое решение капчи с помощью сервисов, таких как 2Captcha или AntiCaptcha, либо можно вручную обрабатывать капчу.

Заключение

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