CoderCastrov logo
CoderCastrov
Node.js

Парсинг веб-страниц с использованием NodeJS

Парсинг веб-страниц с использованием NodeJS
просмотров
6 мин чтение
#Node.js

Извлечение данных с веб-сайта, создание новых источников данных и контроль форматирования.

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

Чтобы узнать о юридических и незаконных последствиях, прочитайте эту информативную статью от Data Science Academy: http://datascienceacademy.com.br/blog/web-scraping-e-web-crawling-sao-legais-ou-ilegais/

Введение

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

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

Например, если я хочу создать набор данных о фильмах для анализа тенденций выпуска фильмов с течением времени. Если я извлекаю данные о фильмах с сайтов, таких как IMDB, обычно я заинтересован только в части этой структуры, такой как ссылки, изображения, год выпуска, бюджет фильма, жанр и т. д. Большая часть исходной структуры будет отброшена, потому что она не подходит для моей цели анализа полученных данных.

Парсинг vs Краулер

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

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

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

Структура Парсера, которую я покажу, не способна работать с динамическими страницами, такими как бесконечная загрузка, например. Для этого вам понадобится инструмент, способный рендерить этот JavaScript, если это ваша потребность, следуйте этому пути: https://github.com/puppeteer/puppeteer.

APIs не растут на деревьях

Я обычно рассматриваю API (Application Programming Interface) как:

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

API может обслуживать запросы из разных источников одновременно.

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

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

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

Недавно один из наших клиентов попросил нас разместить на его сайте данные университета, которые показывали в очень конкретном формате риск того, что рабочие места будут "заменены роботами". Хотя университет разрешил извлечение этих данных, у них не было никакого способа предоставления данных, и это осталось "нашей заботой".

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

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

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

Hands-On

На основе предыдущего примера я воссоздал простой сценарий и буду использовать Mercado Livre в качестве объекта тестирования, не вмешиваясь в стабильность его серверов.

Справочная информация о данных

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

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

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

Атрибуты, которые мы хотим извлечь из каждого элемента.

Чтобы создать эту структуру, нам нужно получить доступ к веб-сайту и понять HTML-разметку каждого элемента, который мы хотим получить, и узнать, как получить к нему доступ с помощью CSS-селекторов. Например, для каждого элемента структура изображения выглядит следующим образом:

**.results-item > .item .item__image .images-viewer img**

Рекомендую быть максимально точным и избегать слабых элементов, таких как span, для создания вашей ссылки, поскольку они могут легко измениться.

Пример HTML-разметки, Изображение товара.

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



Реализация на NodeJS

Мы будем использовать библиотеку с открытым исходным кодом Scrape-It, которая предоставляет абстракцию для создания логики парсинга. Для получения более подробной информации ознакомьтесь с документацией.

С помощью трех простых методов мы сможем достичь ожидаемого результата. Репозиторий проекта находится здесь: https://github.com/marcosfreitas/scraping-mercado-livre.

Это метод, отвечающий за выполнение запроса. Библиотека возвращает Promise, и с помощью async/await в JavaScript мы можем дождаться завершения запроса, чтобы вернуть результат.

В качестве параметров мы передаем URL и набор объектов, которые являются ссылками на элементы, которые мы хотим получить на сайте, и в то же время этот объект является форматом, в котором мы получим ответ.

const scrapeIt = require("scrape-it");

async function makeRequest(url, config) {
  const { data } = await scrapeIt(url, config);
  return data;
}

В атрибуте items мы вызываем другой метод, который содержит только эту структуру, getJSONFormat:

function getJSONFormat() {
  return {
    items: {
      listItem: ".item",
      data: {
        name: ".item__name",
        price: {
          selector: ".item__price",
          convert: (value) => parseFloat(value.replace("$", "").replace(",", ".")),
        },
        image: {
          selector: ".item__image",
          attr: "src",
        },
      },
    },
  };
}

Обратите внимание, что для получения правильного значения атрибутов price и image нам пришлось выполнить преобразование (convert), которое обрабатывает HTML-структуру полученного элемента, чтобы получить более подходящее значение в ответе.

Наконец, в методе search при возврате функции вызывается метод responseSlice, который извлекает часть ответа, соответствующую запрашиваемому лимиту элементов.

function responseSlice(response, limit) {
  return response.slice(0, limit);
}

async function search(req, res) {
  const { query } = req.query;
  const url = `https://www.example.com/search?q=${query}`;
  const config = getJSONFormat();

  const data = await makeRequest(url, config);
  const items = responseSlice(data.items, 10);

  res.json(items);
}

Эти методы принадлежат структуре API, поэтому они имеют маршрут для поиска. В репозитории проекта вы можете изучить всю эту структуру и запустить API или адаптировать ее для своего сценария.

const express = require("express");
const app = express();

app.get("/search", search);

app.listen(3000, () => {
  console.log("Server is running on port 3000");
});

Заключение

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

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

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

Полезные ссылки

Парсинг и парсеры, а также юридические и незаконные детали.Репозиторий проекта.Определения API.