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

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

1- Настройка проекта

Сначала нам нужно инициализировать наш проект

mkdir real-time-tweet-streamer
cd real-time-tweet-streamer
npm init

Далее мы установим некоторые пакеты, также известные как зависимости:

npm install express ejs node-tweet-stream request socket.io dotenv 

Express: это серверная веб-инфраструктура, основанная на NodeJS. Express поможет нам создать внутреннюю логику, API.

Socket.io: библиотека JavaScript, которая обеспечивает двустороннюю связь между клиентом и сервером в режиме реального времени.

ejs: механизм шаблонов помогает создавать и генерировать HTML-страницы и вставлять данные в HTML-шаблон с помощью простого JavaScript.

node-tweet-stream: модуль твиттера узла, который подключается к общедоступному потоку твиттера. n.t.s поможет нам отслеживать список ключевых слов.

dotenv: модуль, который позволяет получить доступ к переменным среды в нашем приложении.

2- Учетные данные

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

API_KEY="your api key here"
API_SECRET_KEY="your api secret key here"
ACCESS_TOKEN="your access token here"
ACCESS_TOKEN_SECRET="your secret access token here"

3- Создайте код на стороне сервера

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

.
├── public
│   ├── images
│   │   └── Twitter_Logo_Blue.png
│   ├── javascripts
│   │   └── socket-cli.js
│   └── stylesheets
│       └── styles.css
├── routes
    └── index.js
├── views
    └── index.ejs
├── config-streamer.js
├── server.js
├── package.json
└── package-lock.json

Общедоступно: будут содержаться все статические файлы (таблицы стилей, файлы JS, изображения и т. д.).

Маршруты: содержат наши контроллеры приложений, где мы будем отображать HTML-страницу для отображения запрошенных данных.

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

touch server.js

Во-первых, нам нужно создать сервер Node. server.js будет содержать всю внутреннюю логику для подключения и получения твитов от стримера твитов.

  • Содержимое server.js будет следующим:

Мы собираемся настроить приложение со всеми установленными зависимостями и настроить приложение для использования EJS.

const express = require('express')
const path = require('path')
const http = require('http')
const app = express()
const port = process.env.PORT || 9000
const server = http.createServer(app)
//setting a socket.io server
const { Server } = require('socket.io')
const io = new Server(server)
//setting static and views paths 
app.set('views', path.join(__dirname, 'views'))
app.set('view engine', 'ejs')
app.use(express.json())
app.use(express.urlencoded({extended: true}))
app.use(express.static(path.join(__dirname, 'public')))
// use the created index route  
const indexRouter = require('./routes/index')
app.use('/', indexRouter);

//setting the tweets streamer event handlers
const twitter = require('./config-streamer')
const MAX_TWEETS = 10
let tweets = []
twitter.on('tweet', tweet => {
  io.emit('tweet', tweet);
  tweets.unshift(tweet);
  tweets = tweets.slice(0, MAX_TWEETS);
});
server.listen(port, () => {
  console.log(`listening on http://localhost:${port}`)
})

Обратите внимание, что вы должны инициализировать новый экземпляр socket.io, передав объект server (HTTP-сервер).

4- клиент Twitter

Далее мы создадим файл с именем config-streamer.js, где у нас есть клиент Twitter, используя настроенные учетные данные в .envfile.

touch config-streamer.js
  • Содержимое config-streamer.js будет следующим:
const Twitter = require('node-tweet-stream')
const dotenv = require('dotenv')
dotenv.config()
const twitter = new Twitter({
  consumer_key: process.env.API_KEY,
  consumer_secret: process.env.API_SECRET_KEY,
  token: process.env.ACCESS_TOKEN,
  token_secret: process.env.ACCESS_TOKEN_SECRET
})
// we are tracking the word javascript for now 
 
twitter.track('javascript')
twitter.on('error', err => {
  console.error(err);
});
module.exports = twitter

5 – Клиентский код

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

touch routes/index.js 

Добавьте следующий код в файл index.js:

const express = require('express')
const router = express.Router()
router.get('/', (req, res) => {
  res.render('../views/index', {
    title: "Home page"
  })
})
module.exports = router

Обратите внимание, как код отправляет представление клиенту с помощью res.render()

поэтому этот последний вызов будет искать представление для отображения в каталоге представлений. Итак, нам нужно только определить views/index.ejs

touch views/index.ejs

Добавьте следующий код в index.ejs

<!DOCTYPE html>
<html lang="en">
 <head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title><%= title %></title>
  <link rel="stylesheet" href="/stylesheets/styles.css">
 </head>
 <body>
  <div class="root">
   <div class="App">
    <div class="header">
     <img
      class="header-logo"
      src="/images/Twitter_Logo_Blue.png"
     >
     <div class="header-nav">
      <div class="header-option">
       <span class="header-optionLineOne">GitHub</span>
       <span class="header-optionLineTwo">account</span>
      </div>
      <div class="header-option">
       <span class="header-optionLineOne">LinkedIn</span>
       <span class="header-optionLineTwo">account</span>
      </div>
     </div>
    </div>
    <div class="home">
     <div class="home-container">
      <div class="home-row" id="tweets"></div>
     </div>
    </div>
   </div>
  </div>
  <script src="/socket.io/socket.io.js"></script>
  <script src="/javascripts/socket-cli.js"></script>
 </body>
</html>

index.ejsБудет ли файл содержать представление индексной страницы.

Установите <div class="home-row" id="tweets" >, где мы будем отображать содержимое твита каждый раз, когда получаем новый твит.

Затем создайте новый файл с именем public/javascripts/socket-cli.js и добавьте следующий код.

var socket = io();
var tweetsArea = document.getElementById('tweets')
socket.on('tweet', function(tweet) {
 const content = `
  <div class="tweet">
   <div class="box">
    <article class="media">
     <div class="media-left">
      <figure class="image is-64x64" >
       <img src=${tweet.user.profile_image_url} alt="Image" />
      </figure>
     </div>
     <div class="media-content">
      <div class="content">
       <p>
        <strong>${tweet.user.name}</strong>
        <small>@${tweet.user.screen_name}</small><br />
        ${tweet.extended_tweet ? tweet.extended_tweet.full_text : tweet.text} 
       </p>
      </div>
      <div class="level-left">
       <div class="level-item">
        <span><small>${ tweet.created_at}</small></span>
        <button class="btn">
         <a href="${getUrlsFromText(tweet.text)[0]}">See TWEET</a>
        </button>
       </div>
      </div>
     </div>
    </article>
   </div>
  </div>
 `
 tweetsArea.innerHTML += content
 window.scrollTo(0, document.body.scrollHeight)
})

для загрузки socket.io-client требуется только первая строка var socket = io(), которая предоставляет глобальную io (и конечную точку GET), а затем подключается.

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

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

Итак, после запуска nodemon server.js

результат должен быть следующим:

не забудьте добавить файл таблицы стилей, поэтому в каталоге public/stylesheets добавьте файл с именем styles.css и добавьте следующий код

body {
   margin: 0;
   font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen','Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',sans-serif;
   -webkit-font-smoothing: antialiased;
   -moz-osx-font-smoothing: grayscale;
    background: #e6ecf1;
}
.header {
height: 60px;
display: flex;
align-items: center;
background-color: #131921;
position: sticky;
top: 0;
z-index: 100;
}
.header-logo {
width: 100px;
object-fit: contain;
margin: 0 20px;
margin-top: 18px;
}
.header-optionLineTwo {
font-size: 10px;
}
.header-optionLineOne {
font-size: 13px;
font-weight: 800;
}
.header-nav {
display: flex;
justify-content: space-evenly;
}
.header-option {
display: flex;
flex-direction: column;
margin-left: 10px;
margin-right: 10px;
color: white;
}
.home {
display: flex;
justify-content: center;
margin-left: auto;
margin-right: auto;
max-width: 1500px;
}
.tweet {
margin: 10px;
padding: 20px;
width: 100%;
max-height: 400px;
background-color: white;
}
.box {
margin-bottom: 0;
border-radius: 0;
}
.content small {
color: #1da1f2;
}
.level-item {
padding-right: 10px;
color: #c3c3c3;
}
.media-left {
margin-right: 1rem;
}
.media{
display: flex;
align-items: flex-start;
text-align: left;
}
.image {
display: block;
position: relative;
}
.image > img {
display: block;
height: auto;
width: 100%;
border-radius: 30px;
}
.image.is-64x64 {
height: 64px;
width: 64px;
}
.tweet-info {
height: 100px;
margin-bottom: 15px;
}
.control {
font-size: 1rem;
position: relative;
text-align: left;
}
.btn{
border: none;
color: white;
background-color: #1da1f2;
padding: 10px 9px;
text-align: center;
margin: 16px 16px !important;
text-decoration: none;
cursor: pointer;
font-size: 11px;
}

Заключение

В этой статье мы узнали, как использовать Twitter API для потоковой передачи твитов с заданными ключевыми словами.

Использование socket.io позволяет получать данные в режиме реального времени. Обратитесь к документации socket.io, чтобы получить дополнительную информацию о интересных вещах и функциях.

Код можно найти на GitHub ЗДЕСЬ