Cheerio против Puppeteer для парсинга веб-страниц

Давайте рассмотрим, в чем различия между Puppeteer и Cheerio на примере создания парсера с их помощью.
5 min read
Cheerio vs. Puppeteer featured image

Cheerio и Puppeteer — это две библиотеки Node.js, которые позволяют вам программно просматривать Интернет. Из-за этого они оба являются популярным выбором для тех, кто хочет создать парсер на node.js с нуля.  

Чтобы сравнить Cheerio и Puppeteer, мы создадим простой парсер с Cheerio и парсер с Puppeteer. Мы будем использовать оба инструмента для извлечения всех ссылок на блоги из In Plain English, популярной платформы для программирования.

Прежде чем мы начнем, давайте посмотрим, что мы обсудим в этой статье:

Отличия между Cheerio и Puppeteer

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

Cheerio

  • Cheerio — это анализатор DOM, способный анализировать файлы HTML и XML.
  • Это быстрая и компактная реализация ядра jQuery, разработанная специально для сервера.
  • Если вы планируете применять это для парсинга сайта, вам нужно будет использовать Cheerio в сочетании с клиентской библиотекой Node.js http, такой, как Axios.  
  • Cheerio не отображает сайт как браузер (не применяет CSS и не загружает внешние ресурсы).
  • Из-за этого вам будет сложно парсить SPA, созданные с использованием таких технологий, как React.
  • Cheerio не может взаимодействовать с сайтом (например, не может нажимать кнопки) или получать доступ к содержимому, скрытому за скриптами.
  • Его легко освоить благодаря простому синтаксису. Пользователи jQuery будут чувствовать себя здесь как дома.
  • Cheerio быстрее по сравнению с Puppeteer.

Puppeteer

  • Puppeteer — инструмент автоматизации браузера. Вы получаете доступ ко всему движку браузера (обычно Chromium).
  • Это делает его более универсальным вариантом по сравнению с Cheerio.
  • Он может выполнять JavaScript, что позволяет ему соскабливать динамические страницы, такие, как одностраничные приложения (SPA).
  • Puppeteer может взаимодействовать с сайтами, то есть с его помощью можно нажимать кнопки, вводить данные в формы входа и т. д.
  • У него крутая кривая обучения, так как он имеет больше функций и часто требует использования асинхронного кода (т.е. обещания/асинхронного ожидания).
  • Puppeteer медленный по сравнению с Cheerio.

Создание парсера с Cheerio

Для начала давайте создадим папку с именем scraper для нашего кода. Внутри парсера запустите npm init -y или yarn init -y, в зависимости от того, что вы выбрали: npm или yarn.  

Теперь, когда у нас есть готовая папка и инициализированный package.json, давайте установим наши пакеты.  

Примечание. Вы можете обратиться к нашему основному руководству по парсингу веб-страниц на node.js, в котором более подробно описано использование Cheerio и Axios для веб-скрапинга.  

Шаг 1 — Установка Cheerio

Чтобы установить Cheerio, выполните в терминале следующую команду:

// using npm
npm install cheerio

// or using yarn
yarn add cheerio

Шаг 2 — Установка Axios

Axios — популярная библиотека для выполнения HTTP-запросов в Node.js. Ее можно использовать для вызовов API, получения данных с сайтов и многого другого.

Для установки выполните следующую команду в терминале:

// using npm
npm install axios

// or using yarn
yarn add axios

Мы используем Axios для выполнения HTTP-запросов к сайту, который мы хотим парсить. Ответ, который мы получаем от сайта, имеет форму HTML, который мы затем можем анализировать и извлекать необходимую информацию с помощью Cheerio.

Шаг 3 — Подготовка нашего парсера

Давайте перейдем в папку нашего парсера и создадим файл с именем cheerio.js.  

Вот базовая структура кода, которая поможет вам начать парсинг страниц с помощью Cheerio и Axios:

const axios = require('axios');
const cheerio = require('cheerio');

axios
 .get("https://plainenglish.io/blog")
 .then((response) => {
   // Initialize links array which we will push the links to later
   let links = [];

   // HTML Markup
   const body = response.data;

   // Load HTML data and initialize cheerio
   const $ = cheerio.load(body);

   // CSS selector for the target element
   const element = ".PostPreview_container__82q9E";

   // Loop through each matching element and extract the text content
   $(element).each(function () {
     // Loop through each matching element and get the href attribute of each element
     const _link = $(this).find("a").prop("href");

     // We check if the link is undefined because cheerio will return undefined if the element doesn't exist
     if (_link !== undefined) {
       // Add the link to the links array
       links.push(`https://plainenglish.io` + _link);
     }
   });

   return links;
 })
 .then((response) => {
   console.log(response);
 });

В приведенном выше коде нам сначала нужны библиотеки Axios и Cheerio.

Шаг 4 — Запрос данных

Затем мы делаем запрос get() на «https://plainenglish.io/blog». Поскольку Axios является асинхронным, мы связываем нашу функцию get() с then().  

Мы инициализируем пустой массив ссылок, чтобы собрать линки, которые мы планируем парсить.

Затем мы передаем response.data из Axios в Cheerio с помощью:  

// HTML Markup
const body = response.data;

// Load HTML data and initialize cheerio
const $ = cheerio.load(body);
We choose which selector we plan to target, in our case:
// CSS selector for the target element
const element = ".PostPreview_container__82q9E";

Шаг 5 – Обработка данных

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

// Loop through each matching element and extract the text content
$(element).each(function () {
 // Loop through each matching element and get the href attribute of each element
 const _link = $(this).find("a").prop("href");

 // We check if the link is undefined because cheerio will return undefined if the element doesn't exist
 if (_link !== undefined) {
   // Add the link to the links array
   links.push(`https://plainenglish.io` + _link);
 }
});

Затем мы возвращаем ссылки, выполняем еще одну цепочку then() и console.log нашего ответа.  

Шаг 6 – Конечные результаты

Наконец, если мы откроем терминал из папки парсера, мы сможем запустить node.js и cheerio.js. Это выполнит весь код из нашего файла cheerio.js. Вы должны увидеть, что URL-адреса из нашего массива ссылок будут выведены на консоль. Это будет выглядеть примерно так:  

 'https://plainenglish.io/blog/how-to-implement-a-search-bar-in-react-js',
 'https://plainenglish.io/blog/how-to-build-data-driven-surveys-with-react-rest-api-surveyjs',
 'https://plainenglish.io/blog/handle-errors-in-angular-with-httpclient-and-rxjs',
 'https://plainenglish.io/blog/deploying-a-localhost-server-with-node-js-and-express-js',
 'https://plainenglish.io/blog/complete-guide-to-data-center-migration',
 'https://plainenglish.io/blog/build-a-stripe-app-with-typescript-and-node-js-part-2',
 ... 861 more items

И вот так нам удалось выполнить парсинга сайта In Plain English!

Отсюда мы можем сделать еще один шаг и сохранить данные в файл, а не просто вывести их в консоль.

Cheerio и Axios упрощают парсинг веб-страниц в Node.js. С помощью всего нескольких строк кода вы можете извлекать данные с сайтов и использовать их для различных целей.  

Создание парсера с помощью Puppeteer

Давайте зайдем в нашу папку парсера и создадим файл с именем puppeteer.js. Мы уже инициализировали наш package.json, но если вы пропустили этот шаг, перейдите к инициализации этого файла  

После инициализации перейдем к установке Puppeteer.

Шаг 1 — Установка Puppeteer

Чтобы установить Puppeteer, выполните одну из следующих команд:

// using npm
npm install puppeteer

// or using yarn
yarn add puppeteer

Шаг 2 — Подготовка нашего парсера

Давайте зайдем в нашу папку парсера и создадим файл с именем puppeteer.js.  

Вот базовая структура кода, с которой можно начать парсинг веб-страниц с помощью Puppeteer:

const puppeteer = require("puppeteer");

// Because everything in Puppeteer is asynchronous,
// we wrap all of our code inside of an async IIFE
(async () => {
 // Initialize links array which we will push the links to later
 let links = [];

 // Launch Puppeteer
 const browser = await puppeteer.launch();

 // Create a new page
 const page = await browser.newPage();

 // Go to URL
 await page.goto("https://plainenglish.io/blog");

 // Set screen size
 await page.setViewport({ width: 1080, height: 1024 });

 // CSS selector for the target element
 const element = ".PostPreview_container__82q9E";

 // Get all matching elements
 const elements = await page.$$(element);

 // Wrapped with Promise.all to wait for all promises to resolve before continuing
 const _links = await Promise.all(
   // Get the href attribute of each element
   elements.map(async (el) => el.evaluate((el) => el.children[0].href))
 );

 if (_links.length) {
   // If there are any links
   _links.forEach((url) => {
     // Loop through each link
     links.push(url); // Add the link to the links array
   });
 }

 console.log(links);

 await browser.close();
})();

В приведенном выше коде нам сначала требуется библиотека Puppeteer:

Шаг 3 — Создание IIFE

Далее мы создадим выражение функции с немедленным вызовом (IIFE). Поскольку в Puppeteer все асинхронно, мы ставим async в начале. Другими словами, получается следующее:  

(async () => {
// ...code goes here
}()

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

// Initialize links array which we will push the links to later
let links = []

Затем мы запускаем Puppeteer, открываем новую страницу, переходим по URL-адресу и устанавливаем область просмотра страницы (размер экрана).

 // Launch Puppeteer
 const browser = await puppeteer.launch();

 // Create a new page
 const page = await browser.newPage();

 // Go to URL
 await page.goto("https://plainenglish.io/blog");

 // Set screen size
 await page.setViewport({ width: 1080, height: 1024 });

По умолчанию Puppeteer работает в «безголовом режиме». Это означает, что он не открывает браузер, который вы можете видеть визуально. Тем не менее мы по-прежнему устанавливаем размер области просмотра, так как хотим, чтобы Puppeteer просматривал сайт с определенной шириной и высотой.

Примечание. Если вы решите, что хотите наблюдать за работой Puppeteer в режиме реального времени, вы можете передать параметр headless: false в качестве параметра, как показано ниже:  

// Launch Puppeteer
const browser = await puppeteer.launch({ headless: false });

Шаг 4 — Запрос данных

Отсюда мы выбираем, на какой селектор мы планируем ориентироваться, в нашем случае:

// CSS selector for the target element
const element = ".PostPreview_container__82q9E";

И запустите то, что является своего рода эквивалентом querySelectorAll() для нашего целевого элемента:  

// Get all matching elements
const elements = await page.$$(element);

Примечание: $$ — это не то же самое, что querySelectorAll, поэтому не ожидайте, что у вас будет доступ к одним и тем же вещам.  

Шаг 5 – Обработка данных

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

// Wrapped with Promise.all to wait for all promises to resolve before continuing
const _links = await Promise.all(
 // Get the href attribute of each element
 elements.map(async (el) => el.evaluate((el) => el.children[0].href))
);

В нашем конкретном случае использования у нас есть el.children[0], так как я знаю, что первый дочерний элемент нашего целевого элемента — это тег, и это именно тот тег, значение которого я хочу получить.  

Затем мы проходим по каждому отображаемому элементу и помещаем значение в наш массив ссылок, например:

if (_links.length) {
 // If there are any links
 _links.forEach((url) => {
   // Loop through each link
   links.push(url); // Add the link to the links array
 });
}

Наконец, мы выводим ссылки в консольный журнал console.log, а затем закрываем браузер:  

console.log(links);

await browser.close();

Примечание. Если вы не закроете браузер, он останется открытым, и ваш терминал зависнет.  

Шаг 6 – Конечные результаты

Теперь, если мы откроем терминал из папки парсера, мы сможем запустить node.js puppeteer.js. Это выполнит весь код из нашего файла puppeteer.js. Вы должны увидеть, что URL-адреса из нашего массива ссылок выводятся на консоль. Это будет выглядеть примерно так:  

'https://plainenglish.io/blog/how-to-implement-a-search-bar-in-react-js',
 'https://plainenglish.io/blog/how-to-build-data-driven-surveys-with-react-rest-api-surveyjs',
 'https://plainenglish.io/blog/handle-errors-in-angular-with-httpclient-and-rxjs',
 'https://plainenglish.io/blog/deploying-a-localhost-server-with-node-js-and-express-js',
 'https://plainenglish.io/blog/complete-guide-to-data-center-migration',
 'https://plainenglish.io/blog/build-a-stripe-app-with-typescript-and-node-js-part-2',
 ... 861 more items

И вот так нам удалось выполнить парсинг сайта с помощью Puppeteer!

Puppeteer — мощный инструмент для парсинга веб-страниц и автоматизации задач браузера. Он предоставляет богатый API для веб-скрапинга и автоматизации задач браузера. Вы можете использовать его для извлечения информации с сайтов, создания скриншотов и PDF-файлов, а также для выполнения многих других задач.

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

Примечание. Существуют и другие альтернативы Puppeteer, такие, как Selenium или IDE веб-парсера. Или, если вы хотите сэкономить время, вы можете полностью пропустить весь процесс парсинга страниц, выбрав готовые наборы данных.  

Выводы

Если вы хотите парсить статические страницы без потребности во взаимодействии, например, клики и отправка форм (или любой обработки событий в этом отношении), Cheerio — оптимальный выбор.

Однако, если сайт использует JavaScript для внедрения контента или вам нужно обрабатывать события, следует выбрать Puppeteer.

Какой бы подход вы ни выбрали, стоит отметить, что конкретно этот вариант использования был довольно простым. Если вы попытаетесь парсить что-то более сложное, например динамический сайт (например, YouTube, Twitter или Facebook), вы можете оказаться в довольно сложном положении.  

Если вы хотите парсить сайты и не тратить недели на то, чтобы собрать решение, вам лучше найти готовое решение, такое как IDE веб-парсера от Bright Data.  

IDE Bright Data включает в себя готовые функции парсинга, встроенную сложную инфраструктуру разблокировки прокси, сценарии браузера на JavaScript, отладку и несколько готовых к использованию шаблонов парсинга для популярных сайтов.