CoderCastrov logo
CoderCastrov
Парсер

Парсинг веб-данных с использованием Parse

Парсинг веб-данных с использованием Parse
просмотров
6 мин чтение
#Парсер

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

Отказ от ответственности: ЭТО ВАЖНО!

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

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

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

Так что убедитесь, что вы ответили на все эти вопросы, прежде чем что-либо парсить:

  • Является ли данный контент авторским или юридически защищенным?
  • Вы прочитали условия использования веб-сайта?
  • Явно ли в условиях использования указано, что вы можете копировать контент?
  • У вас есть электронное письмо или какой-либо документ от владельца, в котором явно указано, что вы можете копировать данные?
  • Предвидите ли вы какие-либо проблемы, если эти данные станут доступны публично?

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

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

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

Поделитесь своими данными!

Основная цель этой статьи - побудить всех собирать, а затем ДЕЛИТЬСЯ своими базами данных в нашей супер-крутой Базе данных Hub.

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

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

Итак, без лишних слов, давайте начнем...

Что мы будем использовать

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

Мы также будем использовать 4 модуля NPM для упрощения нашей разработки:

Итак, следуя нашему руководству по установке модулей NPM на Back4app, у меня получился следующий файл package.json:

{
   "dependencies": {
     "request-promise": "*",
     "request": "*",
     "cheerio": "*",
     "cheerio-tableparser": "*"
   }
}

Наш код

Наша задача будет называться "getStatistics", поэтому давайте начнем кодирование самой задачи, как описано в документации Parse:

Parse.Cloud.job("getStatistics", async (request) =>   {

});

И внутри него давайте создадим экземпляры наших трех модулей (request-promise уже имеет реализацию запроса, поэтому нам не нужно повторно создавать его). Также объявим наш URL, откуда мы будем получать данные.

Parse.Cloud.job("getStatistics", async (request) =>  {
    const rp = require('request-promise');
    const cheerio = require('cheerio');
    const cheerioTableparser = require('cheerio-tableparser');

    const url = 'https://en.wikipedia.org/wiki/2019%E2%80%9320_coronavirus_pandemic_by_country_and_territory'
 })

Теперь давайте используем request-promise (rp) для получения контента. Также поймаем любые возможные исключения, так как мы не хотим, чтобы наша задача просто умерла без объяснения причины:

Parse.Cloud.job("getStatistics", async (request) =>  {
    const rp = require('request-promise');
    const cheerio = require('cheerio');
    const cheerioTableparser = require('cheerio-tableparser');

    const url = 'https://en.wikipedia.org/wiki/2019%E2%80%9320_coronavirus_pandemic_by_country_and_territory'

    rp(url)
        .then(async function(html){
            //успех!
        })  
    .catch(function(err){
        //обработка ошибки
    });
});

Теперь request-promise получил наш контент и передал его (параметр HTML) нашей асинхронной функции. Пришло время загрузить этот HTML-контент в Cheerio:

$ = cheerio.load(html);

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

В моем случае двух классов было достаточно: .wikitable и .plainrowheaders будут уникально идентифицировать эту таблицу и сообщить Cheerio-Tableparser, какую именно таблицу мы ищем.

Вы можете определить, какие классы имеет таблица, которую вы ищете, с помощью инструмента инспектирования Chrome:

Так что наш код для этого будет выглядеть так:

cheerioTableparser($); 
var data = $(".wikitable.plainrowheaders").parsetable(true, true, true);

До сих пор наш полный код выглядит следующим образом:

Parse.Cloud.job("getStatistics", async (request) =>  {
    const rp = require('request-promise');
    const cheerio = require('cheerio');
    const cheerioTableparser = require('cheerio-tableparser');

    const url = 'https://en.wikipedia.org/wiki/2019%E2%80%9320_coronavirus_pandemic_by_country_and_territory'

    rp(url)
        .then(async function(html){
            //успех!

            $ = cheerio.load(html);

            cheerioTableparser($);
            var data = $(".wikitable.plainrowheaders").parsetable(true, true, true);

        })  
    .catch(function(err){
        //обработка ошибки
        console.err('ОШИБКА: ' + err)
    });
});

Теперь мы можем извлечь информацию, которую мы хотим. Я объявил переменные, чтобы хранить эти значения, чтобы все вы могли понять, что я делаю, но вы можете получить доступ к данным напрямую по их позиции в массиве:

let names = data[1]
let cases = data[2]
let deaths = data[3]
let recov = data[4]

Теперь следующим шагом будет перебор этих массивов и заполнение данных в нашем классе, но на этом этапе стоит отметить, что cheerio-tableparse также получит строки, содержащие названия столбцов, поэтому нам придется исключить первые 2 строки из наших массивов: наш цикл не будет начинаться с 0, а с 2 (удаляя строки 0 и 1).

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

const Covid19Case = Parse.Object.extend("Covid19Case");

for (let i = 2; i < names.length-2 ; i ++){
    let thisCovid19Case = new Covid19Case();

    // Заменяет любые символы, которые мы не хотим, такие как запятые для разделителя с плавающей точкой
    let thisName = names[i].replace(/\[.*\]/g, "");
    let thisCases = cases[i].replace(',', '');
    let thisDeaths = deaths[i].replace(',', '');
    let thisRecov = recov[i].replace(',', '');

    // Установка свойств
    thisCovid19Case.set('countryName', thisName)
    thisCovid19Case.set('cases', parseInt(thisCases))
    thisCovid19Case.set('deaths', parseInt(thisDeaths))
    thisCovid19Case.set('recovered', parseInt(thisRecov))
    thisCovid19Case.set('date', new Date())

    // Сохранение
    // Нам нужно использовать Masterkey, если приложение опубликовано на Hub. В противном случае мы этого не делаем
    await thisCovid19Case.save(null,{useMasterKey:true})
}

Теперь давайте посмотрим на наш полный код:

Parse.Cloud.job("getStatistics", async (request) =>  {
    const rp = require('request-promise');
    const cheerio = require('cheerio');
    const cheerioTableparser = require('cheerio-tableparser');

    const url = 'https://en.wikipedia.org/wiki/2019%E2%80%9320_coronavirus_pandemic_by_country_and_territory'

    rp(url)
        .then(async function(html){
            //успех!

            $ = cheerio.load(html);

            cheerioTableparser($);
            var data = $(".wikitable.plainrowheaders").parsetable(true, true, true);

            let names = data[1]
            let cases = data[2]
            let deaths = data[3]
            let recov = data[4]

            const Covid19Case = Parse.Object.extend("Covid19Case");

            for (let i = 2; i < names.length-2 ; i ++){
                let thisCovid19Case = new Covid19Case();

                // Заменяет любые символы, которые мы не хотим, такие как запятые для разделителя с плавающей точкой
                let thisName = names[i].replace(/\[.*\]/g, "");
                let thisCases = cases[i].replace(',', '');
                let thisDeaths = deaths[i].replace(',', '');
                let thisRecov = recov[i].replace(',', '');

                // Установка свойств
                thisCovid19Case.set('countryName', thisName)
                thisCovid19Case.set('cases', parseInt(thisCases))
                thisCovid19Case.set('deaths', parseInt(thisDeaths))
                thisCovid19Case.set('recovered', parseInt(thisRecov))
                thisCovid19Case.set('date', new Date())

                // Сохранение
                // Нам нужно использовать Masterkey, если приложение опубликовано на Hub. В противном случае мы этого не делаем
                await thisCovid19Case.save(null,{useMasterKey:true})
            }
        })  
    .catch(function(err){
        //обработка ошибки
        console.err('ОШИБКА: ' + err)
    });
});

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