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

Как я уже сказал, нам нужны как можно больше всех исторических данных. Таким образом, решением было бы запустить программу ежедневно (ежедневно достаточно). Но как добиться?

Heroku — отличное решение в этом случае. Это очень легко настроить, и это бесплатно, потому что мы не так много используем! Неважно, выберете ли вы другой облачный сервис или что-то еще, но я действительно рекомендую героку в этом сценарии.

В случае, если кто не знаком с героку, рекомендую следовать их инструкции с самого начала https://devcenter.heroku.com/start

Если вы это сделали, теперь вы сможете использовать команду heroku из терминала.

heroku

Начать

В прошлый раз мы получили данные об акциях и сохранили их в файле .json. Теперь мы немного усложним, вместо этого мы будем хранить его в базе данных. В этом случае будет использоваться MongoDB. Heroku также бесплатно предоставляет сервис mongodb до 500 МБ.

Теперь создайте новое приложение в приборной панели heroku.

И после того, как закончим создавать приложение, включим mLab

Если успешно добавить mLab в ваше приложение heroku, heroku предоставит вам URI mongodb.

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

Скопируйте URI, и мы будем использовать его позже!

Кодирование

Для хранения данных в mongodb я буду использовать Mongoosejs. Эта библиотека завершает официальный Mongodb для Nodejs.

Чтобы установить мангуст

npm install mongoose --save

Затем в коде просто требуйте его как обычно, а также настройте mongodb uri следующим образом, а затем подключите mongoose к mongodb URI.

index.js

const mongoose = require('mongoose')
const mongoUri = process.env.MONGOLAB_URI || 'mongodb://yourUriFromHeroku'

mongoose.connect(mongoUri, (err, res) => {
  if (err) {
    console.log ('ERROR connecting to: ' + mongoUri + '. ' + err)
  } else {
    console.log ('Succeeded connected to: ' + mongoUri)
  }
});

Вот и все! Теперь вы сможете запрашивать или сохранять данные о монго в облаке!

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

Напомню старый кодекс,

const cheerio = require('cheerio')
const fetch = require('node-fetch')
const symbol = 'YHOO'
function start() {
 fetch(`http://finance.yahoo.com/q/hp?s=${symbol.toUpperCase()}`)
  .then(res => res.text())
  .then(body => {
    const $ = cheerio.load(body)
    $('.yfnc_datamodoutline1 table tbody')
      .children()
      .each(function(index) {
        if (index === 0) return
        if (!$(this).children().eq(1).text()) return
        var data = {
          date: $(this).children().eq(0).text(),
          open: $(this).children().eq(1).text(),
          high: $(this).children().eq(2).text(),
          low: $(this).children().eq(3).text(),
          close: $(this).children().eq(4).text(),
          volume: $(this).children().eq(5).text(),
        }
      });
  })
}

Это то, что мы сделали в разделе Извлечение данных с веб-сайта с помощью Nodejs (на самом деле я немного обновил код для повышения производительности), но идея осталась прежней.

Что нам нужно сделать, так это сохранить его mongodb. Используя mongoose, вы можете создать объект модели для mongodb.

const Schema = mongoose.Schema
const Stock = mongoose.model('Stock', new Schema({
  symbol: String,
  time: Number,
  open: Number,
  high: Number,
  low: Number,
  close: Number,
  volume: Number
}));

Важная часть здесь. Мы не хотим дублировать данные! КОГДА-ЛИБО!

Вам нужно будет запросить перед сохранением и установить upsert = true, это создаст новый, если он не существует, обновите, если он существовал. Мы будем использовать символ и время как уникальное значение, каждый символ должен иметь только 1 строку данных за 1 день.

function findOneAndUpdate(data) {
  const query = {
    symbol: data.symbol,
    time: data.time
  }
  Stock.findOneAndUpdate(query, data, { upsert: true }, (err, doc) => {
      if (err) return console.log(err)
      return console.log('save success')
   });
}

Теперь у нас есть весь код, давайте объединим его в один кусок.

index.js

const cheerio = require('cheerio')
const fetch = require('node-fetch')
const symbol = 'YHOO'
const mongoose = require('mongoose')
const mongoUri = process.env.MONGOLAB_URI || 'mongodb://yourUriFromHeroku'

const Schema = mongoose.Schema
const Stock = mongoose.model('Stock', new Schema({
  symbol: String,
  time: Number,
  open: Number,
  high: Number,
  low: Number,
  close: Number,
  volume: Number
}));

mongoose.connect(mongoUri, (err, res) => {
  if (err) {
    console.log ('ERROR connecting to: ' + mongoUri + '. ' + err)
  } else {
    console.log ('Succeeded connected to: ' + mongoUri)
    start() // call start after mongodb connected
  }
});

function start() {
  fetch(`http://finance.yahoo.com/q/hp?s=${symbol.toUpperCase()}`)
    .then(res => res.text())
    .then(body => {
      const $ = cheerio.load(body)
      $('.yfnc_datamodoutline1 table tbody')
        .children()
        .each(function(index) {
          if (index === 0) return
          if (!$(this).children().eq(1).text()) return
          var data = {
            date: $(this).children().eq(0).text(),
            open: $(this).children().eq(1).text(),
            high: $(this).children().eq(2).text(),
            low: $(this).children().eq(3).text(),
            close: $(this).children().eq(4).text(),
            volume: $(this).children().eq(5).text(),
          }
          findOneAndUpdate(data) // save data here
        });
    })
}

function findOneAndUpdate(data) {
  const query = {
    symbol: data.symbol,
    time: data.time
  }
  Stock.findOneAndUpdate(query, data, { upsert: true }, (err, doc) => {
    if (err) return console.log(err)
    return console.log('save success')
  });
}

попробуй запустить.

node index.js

Развернуть на Heroku

Чтобы развернуть на героку, следуйте этой инструкции https://devcenter.heroku.com/articles/git

Контрольная работа

Чтобы проверить, может ли heroku запустить вашу программу

cd pathToYourProject
heroku run node index.js

Если вы видите вывод журнала от heroku, значит, он работает!

Расписание выполнения программы ежедневно

Заключительная часть, заставьте heroku ежедневно запускать вашу программу. Heroku также предоставляет работу по расписанию (я уже говорил, heroku отлично подходит для этого случая). https://elements.heroku.com/addons/scheduler

Опять же, перейдите на панель инструментов вашего приложения heroku и добавьте расписание Heroku в качестве надстройки вашего приложения.

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

Сохранить и готово!

Вывод

Я не эксперт в mongodb, если любое предложение будет очень кстати.

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

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