Skip to content

Latest commit

 

History

History

workshop-gathering-information

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 

Сбор данных из сети, парсинг данных, сохранение

  1. Сохранение информации
  2. Предзаданный набор выражений, рандомизация
  3. Генерация данных с помощью библиотек
  4. Получение данных из сторонних API, форматы данных
  5. Получение данных из произвольного места, обработка с помощью регулярных выражений
  6. Обработка изображений, видео, аудио

0. Сохранение

Перед тем, как рассматривать варианты получения информации, нужно знать, как ее сохранить. Систематизированное хранение информации называется базой данных или DataBase. Это отдельная большая область, кратко можно сказать, что базы данных обычно делят на реляционные и нереляционные. Реляционные это такие, которые хранят все в таблицах. Нереляционные это те, которые хрнят данные в виде объектов или деревьев, иерархизированно.

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

Чтобы установить lowdb и начать ей пользоваться

  1. В терминале, перейти в папку проекта (cd)
  2. Установить пакет lowdb npm install lowdb
  3. Написать программу
// загружаем библиотеку в переменную lowdb
var lowdb = require('lowdb')
// создаем файл базы данных
var db = lowdb('data.json')
// добавляем в него изначальные данные (если бд пустая при запуске программы)
db.defaults({data: []}).write()
// теперь в любом месте программы, мы сможем сохранять в данные в массив data
db.get('data').push({id: 1, title: 'test'}).write()

Например, можно сохранять список тех пользователей, кто отправил сообщение вашему чат-боту.

var lowdb = require('lowdb')
var db = lowdb('chatbot.json')
db.defaults({messages: [], users: []}).write()

var Telegram = require('node-telegram-bot-api')
var token = 'HERE_IS_YOUR_TOKEN'
var bot = new Telegram(token, {polling: true})
bot.on('message', function(message) {
  console.log(message)
  // записываем в бд все сообщения без исключения
  db.get('messages').push(message).write()
  // проверяем, если в базе уже есть пользователи с message.from.id
  if (!db.get('users').find({id: message.from.id}).value()) {
    // если такого нет, записываем
    db.get('users').push(message.from).write()
  }
})

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

// объявляем функцию
var sendNotifications = function () {
  // записываем всех пользователей в переменную
  var users = db.get('users').value()
  // проходимся по всем пользователям
  users.forEach(function (user, index) {
    // отправляем каждому сообщение
    bot.sendMessage(user.id, 'kuku, ' + user.first_name)
  })
}
// вызываем функцию при старте программы
sendNotifications()
// настраиваем интервал запуска функции
setInterval(sendNotifications, 1000 * 60 * 60)

1. Предзаданный набор выражений, рандомизация

Вариант, когда у вас уже есть информация, которую вы хотите использовать в каком-то заданном порядке или рандомно. Для этого в JavaScript можно использовать массивы: []. Пример такого массива:

// массив с ответами
var answers = [
  'Ответ номер один',
  'Второй ответ',
  'Ответ # 3',
  'Четвертый ответ'
]

console.log(answers[1])
// выведет в косоль 'Второй ответ'
// так как индекс элементов в массиве начинается с 0

У каждого типа данных есть специальные методы и параметры. Например у массива (которым является переменная answers) есть параметр length (answers.length), который содержит в себе длинну этого массива. С помощью него можно получить случайный элемент этого массива. Например:

// можем создать универсальную функцию, которая принимает
// массив и выдает случайный его елемент
function getRandomValue (array) {
  var randomIndex = Math.floor(Math.random() * array.length)
  return array[randomIndex]
}
console.log(getRandomValue(answers))

2. Генерация данных с помощью библиотек

Существует некоторое количество генераторов, или больших предзаданных списков, которые могут генерировать имена, фотографии, адреса и другую информацию. Обычно применяется для заполнения данными пустых макетов. Пример таких библиотек: chancejs, Faker.js

Чтобы установить такую библиотеку, как обычно, нужно выполнить команду install в терминале npm install faker. И добавить код в наш файл

var faker = require('faker')
// опционально, можно задать язык генерации
// (найдено в документации faker.js)
faker.locale = 'ru'
console.log(faker.fake('{{name.lastName}}, {{name.firstName}} {{name.suffix}}'))

3. Получение данных из сторонних API

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

Список порталов открытых данных

Форматы данных

Существуют разные форматы, в которых данные могут отдаваться этими сервисами. Это значит, что когда мы получаем данные, они приходят к нам в виде простого набора символов. Чтобы набор символов превратился в переменную, например в массив ссылок на картинки, нужно его предварительно обработать. Такую обработку (выделение данных из набора символов называют парсинг)

  • Наиболее распространенный формат JSON расшифровывается как JavaScript Object Notation, поддерживается в JS без дополнительных библиотек. Пример:

    // пример формата JSON
    var jsonString = `
    {
      "pictures": [
        {"url": "http://url.com/1"},
        {"url": "http://url.com/2"}
      ]
    }
    `
    // функция, которая превратит строку в объект
    var object = JSON.parse(jsonString)
    // выведет часть объекта в консоль
    console.log(object.pictures[0].url)
    // в случае, если этот json отдается сервером, можно использовать библиотеку request
    var request = require('request')
    var url = 'https://url.com/data.json'
    request.get(url, function (headers, response) {
      // проверяем наличие ошибок
      if (response.statusCode !== 200) return
      // парсим результаты запроса
      var object = JSON.parse(response.body)
      console.log('object', object)
    })

    В случае, если данные находятся не в сети, а в JSON-файле на вашем компьютере, можно использовать обычный вызов require с путем к этому файлу, чтобы получить готовый объект

      var object = require('./data.json')
      console.log('object', object)
  • Второй по популярности формат: XML, расшифровывается как eXtensible Markup Language, выглядит примерно как HTML, так как HTML и есть сабсет XML. Для получения данных в этом формате, нужно будет использовать библиотеку. Например: xml2js

  • Менее распространенный формат это CSV, или Comma Separated Values, обычно применяется для больших массивов данных. Тоже потребует специальную библиотеку, например csvtojson

  • Другие типы данных, также могут иметь библиотеки для node.js для их парсинга/форматирования. Например, стандартизированный формат RSS/ATOM также имеет пакет для работы с ним, который несложно найти: feedparser.

4. Получение данных из произвольного места в тексте

Но не вся информация может быть получена через официальные API. Часто API либо не существует, либо есть ограничения на его использование. Например, сайт, который выдает координаты Voyager 1, но не имеет API

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

Регулярные выражения

Это язык поиска и осуществления манипуляций с текстом, основанный на использовании метасимволов. Для поиска используется строка-образец (англ. pattern, по-русски её часто называют «шаблоном», «маской»), состоящая из символов и метасимволов и задающая правило поиска. (wikipedia)

Примеры метасимволов:

Символ Соответствие
\d Цифровой символ
\D Нецифровой символ
\s Пробельный символ
\S Непробельный символ
\w Буквенный или цифровой символ или знак подчёркивания
\W Любой символ, кроме буквенного или цифрового символа или знака подчёркивания
Символ Число повторений Пример Соответствие
? Ноль или одно colou?r color, colour
* Ноль или более colou*r color, colour, colouur и т. д.
+ Одно или более colou+r colour, colouur и т. д. (но не color)

Полезные материалы по теме:

Пример 1. Получение данных со страницы про Voyager 1

var request = require('request')
var url = 'https://theskylive.com/voyager1-tracker'
request.get(url, function (headers, response) {
  // находим в исходном тексте строку
  // <span id="dissun">20685553999</span>
  // составляем по ней регулярное выражение
  var matches = /id="dissun">(\d+)<\/span>/gm.exec(response.body)
  // выводим matches[1] в консоль
  console.log('coordinateX', matches[1])
})

Пример 2. Получение данных об оценках

Небольшая программа, которая проходит по всем фотографиям на сайте club.foto.ru и собирает оценки, оставленные его пользователями, к каждой фотографии.

var request = require('request')

function getPhotoMarks (photoId, cb) {
  var baseUrl = 'http://club.foto.ru/gallery/photos/photo.php?photo_id='
  request.get(baseUrl + photoId, function (error, response) {
    if (error || response.statusCode !== 200) return console.error('ошибка запроса, фотография:', photoId)
    // находим в исходном тексте любой страницы с фотографией строку
    // <a title='Статистика оценок' id='marks_public' href='/gallery/photo_statistic.php?photo_id=2510325'>[0|0|0|34]</a>
    // составляем по ней регулярное выражение
    var matches = /id='marks_public'.+?>\[(.+?)\]</gm.exec(response.body)
    // проверяем наличие результата
    // если ничего не найдено, выводим ошибку
    if (matches == null || matches[1] == null) return console.error('ничего не найдено, фотография:', photoId)
    // выводим matches в консоль
    var marks = matches[1].split('|')
    // формируем объект, который будет сохранен
    var result = {
      photoId: photoId,
      marks2: marks[0],
      marks3: marks[1],
      marks4: marks[2],
      marks5: marks[3]
    }
    console.log(result)
  })
}

// пример тестового выполнение функции
getPhotoMarks(2510325)

Теперь, в программу остается только добавить сохранение результатов и цикл по всем фотографиям на сайте. Пример такого цикла:

// цикл на первую 1000 фотографий
// функция getPhotoMarks 'обернута' в функцию setTimeout, которая добавляет
// задержку между запросами (где 1000 – это миллисекунды = 1 секунда),
// это нужно, чтобы вашего бота не заблокировали
for (var i = 1; i <= 1000; i++) {
  setTimeout(getPhotoMarks, 1000 * i, i)
}

5. Обработка изображений, видео, аудио

Существует возможность также выполнять другие программы изнутри нашей программы. Например, редактировать изображения с помощью популярной программы с интерфейсом командной строки graphicMagic или редактировать аудио и видео с помощью ffmpeg. Подробное описание и инструкции вы найдете по ссылкам на эти программы. Мы же рассмотрим пример обработки изображения.

  1. Нужно установить пакет gm (в терминале, в папке проекта ввести npm install gm)
  2. Установить программу graphicsmagick
    • Для мак это можно сделать с помощью homebrew: brew install graphicsmagick
    • Для windows скачать и установить
  3. Написать код
    // загружаем программу в переменную gm
    var gm = require('gm')
    
    // вводим путь к картинке на жестком диске
    // '/path/to/image.jpg' и 'image-out' нужно заменить на свой
    var inPath = '/path/to/image.jpg'
    var outPath = '/path/to/image-out.jpg'
    
    // рисуем на картинке круг и пишем 'привет!'
    gm(inPath).resize(353, 257)
    .stroke('#ffffff')
    .drawCircle(10, 10, 20, 10)
    .fontSize(12)
    .drawText(30, 20, 'Привет!')
    .write(outPath, function (err) {
      // если есть ошибка, выводим ее в консоль
      if (err) return console.error('error', err)
      console.log('saved!')
    })