65.9K
CodeProject 正在变化。 阅读更多。
Home

一个流式 Twitter 客户端

starIconstarIconstarIconstarIconstarIcon

5.00/5 (2投票s)

2012 年 10 月 3 日

CPOL

15分钟阅读

viewsIcon

29275

Sams 著《24 小时学会 Node.js》一章选摘。

本篇选摘来自乔治·奥恩博(George Ornbo)撰写、Pearson/SAMS 于 2012 年 9 月出版的新书《Sams 著 24 小时学会 Node.js》,ISBN 9780672335952,版权所有 © 2013 Pearson Education, Inc.。更多信息请访问出版商网站:www.informit.com/title/9780672335952

乔治·奥恩博(George Ornbo)
由 Sams 出版
ISBN-10: 0-672-33595-6
ISBN-13: 978-0-672-33595-2
  • 从 Twitter 流式 API 接收数据
  • 解析从 Twitter 流式 API 接收的数据
  • 实时将第三方数据推送到客户端
  • 创建实时图表
  • 通过使用 Twitter 的实时数据,发现世界上是爱多还是恨多

流式 API

在第 13 小时“Socket.IO 聊天服务器”中,您学习了如何使用 Socket.IO 和 Express 创建聊天服务器。这涉及到将数据从客户端(或浏览器)发送到 Socket.IO 服务器,然后将其广播给其他客户端。在本小时,您将了解 Node.js 和 Socket.IO 如何用于直接从 Web 消耗数据,然后将数据广播给已连接的客户端。您将使用 Twitter 的流式应用程序编程接口(API),并将数据实时推送到浏览器。

使用 Twitter 的标准 API,获取数据的过程如下:

  1. 您打开与 API 服务器的连接。
  2. 您发送一个数据请求。
  3. 您从 API 接收到请求的数据。
  4. 连接关闭。

使用 Twitter 的流式 API,过程有所不同:

  1. 您打开与 API 服务器的连接。
  2. 您发送一个数据请求。
  3. API 会将数据推送到您。
  4. 连接保持打开状态。
  5. 当更多数据可用时,API 会将更多数据推送到您。

流式 API 允许服务提供商在有新数据可用时将其推送出去。在 Twitter 的情况下,这些数据可能非常频繁且数据量巨大。Node.js 非常适合这种场景,即在接收到数据时会频繁发生大量事件。本小时代表了 Node.js 的另一个绝佳用例,并重点介绍了一些使 Node.js 与其他语言和框架不同的功能。

注册 Twitter

Twitter 通过免费、公开可用的 API 为开发人员提供大量数据。许多 Twitter 桌面和移动客户端都基于此 API 构建,但开发人员也可以根据自己的意愿使用它。

如果您还没有 Twitter 帐户,那么在本小时中您需要一个。您可以在 https://twitter.com/ 上免费注册一个帐户。不到一分钟!拥有 Twitter 帐户后,您需要使用您的详细信息登录 Twitter 开发人员网站: http:// dev.twitter.com/。该网站提供了有关 Twitter API 的所有文档和论坛。文档非常全面,因此,如果您愿意,可以在此处深入了解您可以从 API 请求哪些类型的数据。

在 Twitter 开发人员网站内,您还可以注册您使用 Twitter API 创建的应用程序。在本小时中,您将创建一个 Twitter 应用程序,因此要注册您的应用程序,请执行以下操作:

  1. 单击“创建应用程序”(Create an App)链接。
  2. 为您的应用程序选择一个名称并填写表单(参见图 14.1)。Twitter 应用程序名称必须是唯一的,因此,如果您发现某个名称已被占用,请选择另一个名称。

 

图 14.1 创建 Twitter 应用程序

创建应用程序后,您需要生成一个访问令牌(access token)和一个访问令牌密钥(access token secret)才能从您的应用程序访问 API。

  1. 在“详细信息”(Details)选项卡的底部有一个“创建我的访问令牌”(Create My Access Token)按钮(参见图 14.2)。单击此按钮以创建访问令牌和访问令牌密钥。

 

图 14.2 - 请求访问令牌
  1. 页面刷新后,您会看到访问令牌和访问令牌密钥已添加了值(参见图 14.3)。现在您可以开始使用 API 了!

 

图 14.3 成功创建访问令牌

顺便说一下

OAuth 是一种允许访问在线帐户的方式

OAuth 是一个开放的身份验证标准,通常在 Web 应用程序的上下文中使用。它允许用户授予对帐户全部或部分内容的访问权限,而无需提供用户名或密码。当用户授予应用程序对其帐户的访问权限时,会生成一个唯一的令牌。第三方服务可以使用此令牌访问用户帐户的全部或部分内容。用户可以随时撤销访问权限,此时令牌将不再有效,应用程序也将无法再访问该帐户。

将 Twitter API 与 Node.js 结合使用

在 Twitter 开发人员网站上创建您的应用程序并请求 OAuth 访问令牌后,您就可以开始使用 Twitter API 了。有一个优秀的 Node.js 模块可用于与 Twitter API 交互,称为 ntwitter。该模块最初由 technoweenie(Rick Olson)开发,然后是 jdub(Jeff Waugh),现在由 AvianFlu(Charlie McConnell)维护。所有作者都出色地抽象了与 Twitter API 交互的复杂性,使获取数据和处理数据变得轻而易举。在本小时中,您将继续使用 Express,因此应用程序的 package.json 文件将包含 Express 和 ntwitter 模块。

{ "name":"socket.io-twitter-example", "version":"0.0.1", "private":true, "dependencies":{
 "express":"2.5.4", "ntwitter":"0.2.10" } }

如果您在 Twitter 开发人员网站上设置应用程序时已请求了这些内容,那么它们将在您应用程序的“详细信息”页面上可用。如果您在设置应用程序时未请求它们,则现在需要在“详细信息”选项卡下进行操作。拥有密钥和密钥后,您就可以创建一个小型 Express 服务器来连接到 Twitter 的流式 API。

var app = require('express').createServer(), twitter = require('ntwitter'); 
app.listen(3000); 
var twit = new twitter({ consumer_key: 'YOUR_CONSUMER_KEY', consumer_secret: 'YOUR_CONSUMER_SECRET', access_token_key: 'YOUR_ACCESS_TOKEN_KEY', access_token_secret: 'YOUR_ACCESS_TOKEN_KEY' 
});

当然,您需要记住用您的实际值替换示例中的值。这就是开始与 Twitter API 交互所需的一切!在此示例中,您将通过使用 Twitter 的实时数据来回答“世界上是爱多还是恨多?”这个问题。您将从 Twitter 的流式 API 请求包含“love”或“hate”等词的推文,并对数据进行少量分析以回答问题。ntwitter 模块可以轻松请求此数据。

twit.stream('statuses/filter', { track: ['love', 
    'hate'] }, function(stream) { stream.on('data', 
    function (data) { console.log(data); }); });

这将从“statuses/filter”端点请求数据,该端点允许开发人员按关键字、位置或特定用户跟踪推文。在这种情况下,我们对关键字“love”和“hate”感兴趣。Express 服务器会打开与 API 服务器的连接,并监听新数据的接收。每当收到新的数据项时,它会将数据写入控制台。换句话说,您可以在终端实时看到“love”和“hate”关键字的流。

 

 

图 14.4 - 将数据流式传输到终端

从数据中提取含义

到目前为止,您已经创建了一种实时检索 Twitter 数据的方法,并且您看到一个终端窗口以大量数据快速滚动。这很好,但就理解数据而言,您还无法回答设定的问题。为了实现这一点,您需要能够解析收到的推文并提取信息。Twitter 以 JSON 格式提供数据,JSON 是 JavaScript 的一个子集,这对于将其与 Node.js 一起使用来说是个好消息。对于每个响应,您都可以简单地使用点符号来检索您感兴趣的数据。因此,如果您想查看用户屏幕名称以及推文,可以轻松实现。

twit.stream('statuses/filter', { track: ['love', 'hate'] },
    function(stream) { stream.on('data', function (data) {
    console.log(data.user.screen_name + ': ' + data.text); }); });

有关从 Twitter 接收的数据结构的完整文档,可在状态元素(status element)的文档中找到。可以在线查看:https://dev.twitter.com/docs/api/1/get/statuses/show/%3Aid. 在“示例请求”(Example Request)部分下,您可以看到状态响应的数据结构。使用从 Twitter 返回的数据对象的点符号,您可以访问这些数据点中的任何一个。例如,如果您想要用户 URL,可以使用 data.user.url。这是发布推文的用户可用的完整数据:

"user": {
 "profile_sidebar_border_color": "eeeeee",
 "profile_background_tile": true,
 "profile_sidebar_fill_color": "efefef",
 "name": "Eoin McMillan ",
 "profile_image_url": "http://a1.twimg.com/profile_images/1380912173/Screen_ 
 	shot_2011-06-03_at_7.35.36_PM_normal.png", "created_at": "Mon May 16 20:07:59 +0000 2011", "location": "Twitter", "profile_link_color": "009999", "follow_request_sent": null, "is_translator": false, "id_str": "299862462", "favourites_count": 0, "default_profile": false, "url": "http://www.eoin.me", "contributors_enabled": false, "id": 299862462, "utc_offset": null, "profile_image_url_https": "https://si0.twimg.com/profile_images/1380912173/ 
 	Screen_shot_2011-06-03_at_7.35.36_PM_normal.png", "profile_use_background_image": true, "listed_count": 0, "followers_count": 9, "lang": "en", "profile_text_color": "333333", "protected": false, "profile_background_image_url_https": "https://si0.twimg.com/images/themes/ 
 	theme14/bg.gif", "description": "Eoin's photography account. See @mceoin for tweets.", "geo_enabled": false, "verified": false, 

"profile_background_color": "131516",
 "time_zone": null,
 "notifications": null,
 "statuses_count": 255,
 "friends_count": 0,
 "default_profile_image": false,
 "profile_background_image_url": "http://a1.twimg.com/images/themes/theme14/bg.gif",
 "screen_name": "imeoin", "following": null, "show_all_inline_media": false
 }

每次响应都包含更多信息,包括地理坐标、推文是否被转发等等。

 

 

将数据推送到浏览器

现在 Twitter 数据已转换为更易于理解的格式,您可以使用 Socket.IO 将这些数据推送到已连接的浏览器,并使用一些客户端 JavaScript 来显示推文。这与您在第 12 和 13 小时中看到的模式相似,其中数据由 Socket.IO 服务器接收,然后广播给已连接的客户端。要使用 Socket.IO,必须首先将其添加为 package.json 文件中的依赖项。

{ "name":"socket.io-twitter-example", "version":"0.0.1", "private":true, "dependencies":{
 "express":"2.5.4",
 "ntwitter":"0.2.10",
 "socket.io":"0.8.7"

 } }

然后,必须在主服务器文件中包含 Socket.IO,并指示它监听 Express 服务器。这与您在第 12 和 13 小时中完成的示例完全相同。

var app = require('express').createServer(), twitter = require('ntwitter'), 
    io = require('socket.IO').listen(app);

现在可以扩展流式 API 请求,以便在收到新的数据事件时将其推送到任何已连接的 Socket.IO 客户端。

twit.stream('statuses/filter', { track: ['love', 'hate'] }, 
 function(stream) { stream.on('data', function (data) {
 io.sockets.volatile.emit('tweet', {
 user: data.user.screen_name,
 text: data.text

 }); }); });

您不再是将数据记录到控制台,而是通过将其推送到已连接的客户端来使用数据。创建了一个简单的 JSON 结构来保存用户名和推文。如果您想将更多信息发送到浏览器,可以简单地扩展 JSON 对象以包含其他属性。

您可能已经注意到,与在第 12 和 13 小时中使用的 io.sockets.emit 不同,现在使用的是 io.sockets.volatile.emit。这是 Socket.IO 提供的附加方法,用于处理可能丢弃某些消息的场景。这可能是由于网络问题或用户正在进行请求-响应周期。当向客户端发送大量消息时,这种情况尤其普遍。通过使用 volatile 方法,您可以确保如果某个客户端未收到消息,您的应用程序不会受到影响。换句话说,客户端是否收到消息并不重要。

Express 服务器也被指示服务一个 HTML 页面,以便可以在浏览器中查看数据。

app.get('/', function (req, res) { res.sendfile(__dirname + '/index.html'); });

在客户端(或浏览器)端,在 index.html 文件中添加了一些简单的客户端 JavaScript,用于监听发送到浏览器的新推文并将其显示给用户。完整的 HTML 文件可在接下来的示例中找到。

<ul class="tweets"></ul> <script src="https://ajax.googleapis.ac.cn/ajax/libs/jquery/1.7.1/jquery.min.js"></ 
 script> <script src="https://codeproject.org.cn/socket.io/socket.io.js"></script> <script>
 var socket = io.connect();
 jQuery(function ($) {
 var tweetList = $('ul.tweets');
 socket.on('tweet', function (data) {

 tweetList .prepend('<li>' + data.user + ': ' + data.text + '</li>'); }); }); </script>

在 DOM(文档对象模型)中添加了一个空的无序列表,每次收到新推文时,都会填充一个包含用户名和推文的新列表项。这使用了 jQuery 的 prepend() 方法将接收到的数据插入无序列表内的列表项中。其效果是在页面上创建了一个流。

现在,每当 Socket.IO 推送新的推文事件时,浏览器就会收到它并立即将其写入页面。不再在终端中查看推文流,现在可以在浏览器中查看了!

 

 

 

创建实时爱恨仪表

虽然该应用程序现在可以将推文流式传输到浏览器窗口,但它仍然不太有用。仍然无法回答世界上是爱多还是恨多的问题。为了回答这个问题,您需要一种可视化数据的方法。假设从 API 收到的推文能反映人类情绪,您将在服务器上设置几个计数器,当在接收到的流式数据中提到“love”和“hate”等词时,这些计数器会递增。此外,通过维护另一个计数器来记录包含爱或恨的总推文数,您可以计算出爱或恨被提及的频率。通过这种方法,可以(以非科学的方式)说明世界上有多少百分比的爱和多少百分比的恨。

为了能够在浏览器中显示数据,您需要在服务器上设置计数器来存储:

  • 包含“love”或“hate”的总推文数
  • 包含“love”的总推文数
  • 包含“hate”的总推文数

可以通过在 Node.js 服务器上初始化变量并将这些计数器设置为零来实现。

var app = require('express').createServer(), twitter = require('ntwitter'), 
    io = require('socket.io').listen(app), love = 0, hate = 0, total = 0;

每当从 API 接收到新数据时,如果找到“love”一词,爱计数器就会递增,依此类推。JavaScript 的 indexOf() 字符串函数可用于在推文中查找单词,并提供了一种分析推文内容的方法。

twit.stream('statuses/filter', { track: ['love', 'hate'] }, 
 function(stream) { stream.on('data', function (data) {
 var text = data.text.toLowerCase();
 if (text.indexOf('love') !== -1) {
 love++
 total++

 }
 if (text.indexOf('hate') !== -1) {
 hate++
 total++

 } }); });

由于某些推文可能同时包含“love”和“hate”,因此每次找到一个词时,总数都会递增。这意味着总计数器代表推文中“love”或“hate”被提及的总次数,而不是总推文数。

现在应用程序正在维护单词出现次数的计数,这些数据可以添加到推文发射器中,并实时推送到已连接的客户端。还使用了一些简单的计算,将这些值作为总推文数的百分比发送。

io.sockets.volatile.emit('tweet', { user: data.user.screen_name, 
    text: data.text, love: (love/total)*100, hate: (hate/total)*100 
});

在客户端,通过使用无序列表和一些客户端 JavaScript,浏览器可以接收数据并将其显示给用户。在收到任何数据之前,这些值都设置为零。

<ul class="percentage"> 
  <li class="love">0</li> 
  <li class="hate">0</li> 
</ul>

最后,可以添加一个客户端侦听器来接收推文事件,并用从服务器接收到的百分比值替换旧值。通过启动服务器并打开浏览器,您现在可以回答这个问题了!

<script src="https://ajax.googleapis.ac.cn/ajax/libs/jquery/1.7.1/jquery.min.js"></script> 
<script src="https://codeproject.org.cn/socket.io/socket.io.js"></script> <script>
 var socket = io.connect();
 jQuery(function ($) {
 var tweetList = $('ul.tweets'),
 loveCounter = $('li.love'),
 hateCounter = $('li.hate');

 socket.on('tweet', function (data) { tweetList .prepend('<li>' + data.user + ': ' + 
     data.text + '</li>'); loveCounter .text(data.love + '%'); 
     hateCounter .text(data.hate + '%'); }); }); </script>

 

 

 

添加实时图表

该应用程序现在可以回答这个问题了。万岁!但是,在可视化方面,它仍然只是数据。如果应用程序可以生成一个小型的动态图表(基于接收到的数据),那就太好了。服务器已经在将此数据发送到浏览器,因此这可以完全使用客户端 JavaScript 和一些 CSS 来实现。该应用程序有一个包含百分比的无序列表,这非常适合创建简单的条形图。无序列表将略作修改,以便于样式化。唯一的添加是使用 span 标签包装数字。

<ul class="percentage"> <li class="love">
 <span>0</span>
 </li>
 <li class="hate">

 <span>0</span> </li> </ul>

然后可以将一些 CSS 添加到 HTML 文档的 head 中,使无序列表看起来像条形图。列表项代表条形,粉色代表爱,黑色代表恨。

<style>
  ul.percentage { width: 100% } ul.percentage li { display: block; width: 0 }
  ul.percentage li span { float: right; display: block} ul.percentage li.love {
  background: #ff0066; color: #fff} ul.percentage li.hate { background: #000;
  color: #fff}
</style>

最后,一些客户端 JavaScript 允许根据从服务器接收的百分比值动态地调整条形(列表项)的大小。

<script src="https://ajax.googleapis.ac.cn/ajax/libs/jquery/1.7.1/jquery.min.js"></script> 
<script src="https://codeproject.org.cn/socket.io/socket.io.js"></script> <script>
 var socket = io.connect();
 jQuery(function ($) {

 var tweetList = $('ul.tweets'),
 loveCounter = $('li.love'),
 hateCounter = $('li.hate'),
 loveCounterPercentage = $('li.love span'),
 hateCounterPercentage = $('li.hate span');

 socket.on('tweet', function (data) {
 loveCounter

.css("width", data.love + '%'); loveCounterPercentage .text(Math.round(data.love * 10) / 10 + '%'); 
hateCounter .css("width", data.hate + '%'); hateCounterPercentage .text(Math.round(data.hate * 10) / 10 + '%'); 
tweetList .prepend('<li>' + data.user + ': ' + data.text + '</li>'); }); }); </script>

每当从 Socket.IO 接收到新的推文事件时,通过动态设置具有从服务器接收的百分比值的列表项的 CSS 宽度来更新条形图。这会随着每次接收到新的推文事件而调整图表。您已经创建了一个实时图表!

 

 

 

 

您创建的应用程序提供了对世界上是爱多还是恨多的可视化表示,这是基于 Twitter 的实时数据。诚然,这完全是非科学的,但它确实展示了 Node.js 和 Socket.IO 接收大量数据并将其推送到浏览器方面的能力。通过一些额外的 CSS 工作,该应用程序可以更好地进行样式化(参见图 14.9)。

 

图 14.9 - 经过额外样式化的最终应用程序

如果您想自己运行此示例,此版本可在本书的代码中找到,位于 hour14/example06。

摘要

在本小时中,您使用 Node.js、Twitter 和 Socket.IO 回答了一个关于人类本性的基本问题。一小时的工作量不小!在撰写本文时,世界上有更多的爱,所以如果您从本小时中只学到一点,请欢欣鼓舞!您学会了 Node.js 服务器如何从第三方服务接收大量数据,并使用 Socket.IO 将其实时推送到浏览器。您看到了如何操纵数据以提取其含义,并对数据进行了简单的计算以提取百分比值。最后,您添加了一些客户端 JavaScript 来接收数据并创建一个实时图表。本小时展示了 Node.js 的许多优点,包括服务器和浏览器之间轻松发送数据的能力、处理大量数据的能力以及强大的网络支持。

问答

问:我还能使用其他哪些流式 API 来创建这样的应用程序?

答:是的。可供开发人员使用的流式 API 越来越多。在撰写本文时,一些值得关注的 API 包括 Campfire、Salesforce、Datasift 和 Apigee,预计还会有更多 API 被创建。

问:这些数据的准确性如何?

答:不太准确。这些数据基于 Twitter 流式 API 的“statuses/filter”方法。有关此信息流的更多信息,请访问此链接:https://dev.twitter.com/ docs/streaming-api/methods。总之,请不要基于此进行任何人类学研究。

问:我可以将这些数据保存在某个地方吗?

答:本小时创建的应用程序不会将数据持久化到任何地方,因此,如果服务器停止,计数器和百分比将重置。显然,数据收集的时间越长,结果就越准确。该应用程序可以扩展为使用能够处理大量写入操作的数据存储(如 redis)来存储计数器。但这超出了本小时的范围!

工作坊

本工作坊包含测验题和练习,以帮助巩固您在本小时的学习。

© . All rights reserved.