使用 Node.js、Express、sentiment 和 ntwitter 构建一个情绪分析应用程序

构建一个 Node.js 应用程序来分析公众对 Twitter 上任何给定主题的反应。本文包含一个演示、示例代码和创建基本 PaaS 应用程序的完整说明,然后向该应用程序添加了情绪分析并将它连接到 Twitter。您构建的应用程序将使用流行的 Node.js 模块。在任何需要使用一个快速移动应用程序来不断分析和监视大量数据的时候,都可以重用它。

作为一位软件应用程序开发人员,我尝试过解决以下问题:如何获得来自用户的直接反馈,尤其是在线用户。举例而言,迅速了解 Twitter 用户对一个应用程序、产品发布、活动或当前事件的反应将会很有帮助。反应是正面、负面还是中立的?

由于我希望应用程序能够快速判定 Twitter 上的公众情绪,所以我希望它能够快速开发,连接一个 Twitter Web 服务,拥有一个简单的移动接口,并快速分析海量数据。

借助现有的构建块,您可以非常快地组装一个有趣的小型情绪分析应用程序。

我选择使用 JavaScript 和流行的 Node.js 运行时构建 PaaS 应用程序,将它构建为 PaaS 应用程序。该应用程序使用了 Cloud Foundry 和 Heroku 等 PaaS 环境支持的服务组成编程模型。我选定在 JazzHub 上开发此应用程序。这为我提供了一个地方来发布该应用程序,还提供了一个基于浏览器的不错的 IDE 来开发代码。

运行应用程序

在 JazzHub 上获取代码

构建一个类似应用程序的需求

  • 基本熟悉 Node.js 和 Node.js 开发环境。
  • 以下 Node.js 模块:
    • Express 框架:使得构建 Node.js Web 应用程序变得很轻松。
    • sentiment 模块:对某个字符串执行简单的情绪分析。
    • ntwitter 模块:提供一个简单的 Twitter 接口,包含对 Twitter 的 Stream API 的支持。

观看Node.js 入门(视频演示)

以下步骤描述了最基本的方法。关于能加速您的开发的更高级工具,请参阅 其他工具考虑因素

下面的步骤描述了最基本的方法。关于能加速您的开发的更高级工具,请参阅 其他工具考虑因素


第 1 步. 构建一个 Express 应用程序

  1. 运行 nodenpm 命令:
    图 1. 确认 Node.js 和 NPM 已经安装到您系统上
    运行 node 和 npm 命令的屏幕截图
  2. 创建最简单的 Node.js Express 应用程序:Hello Node.js(请参见 清单 1)。

    在一个新目录中,创建 app.js 文件,这是 Node.js 应用程序的主要文件。告诉 Node.js 需要 Express 模块,然后创建 Express 应用程序。注册一条路由,以便通过 清单 1 中所示的匿名函数处理针对 /hello 的请求。/hello 的处理函数使用 Express 帮助器发送一条简单的文本响应。send 方法处理默认的内容类型和长度等细节。在使用 Express 时,我们可以忽略基础 HTTP 对话的一些细节。

    清单 1. Hello Node.js
    var port = (process.env.VCAP_APP_PORT || 3000);
    var express = require("express");
    
    var app = express();
    
    app.get('/hello', function(req, res) {
        res.send("Hello world.");
    });
    
    app.listen(port);
    console.log("Server listening on port " + port);

    备注:该程序还可以更简单,而且一些附加的代码行可以让它在 CloudFoundry 运行时中运行。在 CloudFoundry 中,该应用程序将重新定位到不同的端口(该端口可从环境中发现)。

  3. 为 Node.js 提供关于该应用程序的一些附加信息,如 清单 2 中所示。

    创建一个 package.json 文件,告诉该应用程序将使用 Express 模块,然后将该应用程序命名为 “Simple Sentiment Analysis App”。因为这个应用程序不会发布到 NPM 注册表,所以您可将它标记为私有。最后,声明该应用程序依赖于 Express 模块的 3.x 版。

    清单 2. package.json
    package.json for Hello Node
    {
      "name": "SimpleSentimentAnalysisApp",
      "description": "Simple Sentiment Analysis App",
      "version": "0.9.0",
      "private": true,
      "dependencies": {
        "express": "3.x"
      }
    }

运行和测试您的 Hello Node.js 应用程序

接下来,执行以下步骤运行和测试 Hello Node.js 应用程序:

  1. 运行您的应用程序之前,准备好节点环境,使用 NPM 抓取为应用程序(和它们的依赖关系等)声明的依赖关系。
    图 2. 准备好节点环境
    运行 npm install 命令的屏幕截图

    成功的 NPM install 会创建 node_modules 目录,其中填入了所需的模块。

  2. 在命令行键入 node app.js
    图 3. 运行 node app.js 命令
    运行 node app.js 命令的屏幕截图

    消息 “Server listening on port 3000” 确认应用程序已启动并在监听请求。

  3. 在浏览器中打开 http://localhost:3000/hello,以测试应用程序的行为。
    图 4. 测试应用程序的行为
    在浏览器中打开 //localhost:3000/hello 的屏幕截图

第 2 步. 向您的应用程序添加情绪分析

现在已经在运行您的基本应用程序,并且环境已设置,是时候使用 Andrew Sliwinsky 开发的非常酷的 sentiment 模块来添加一些实际功能了。他将它描述为 “一个使用 AFINN-111 单词表在任意的输入本文块上执行情绪分析的 Node.js 模块。” 您会看到,这是情绪分析的一种相对简单的实现。它使用一个已分类为正面或负面情绪的英文单词词典对文本中的单词进行评级。

  1. 要开始使用 sentiment 模块,可更新 package.json 以包含它作为一个依赖项:
    清单 3. 更新 package.json
    {
      "name": "SimpleSentimentAnalysisApp",
      "description": "Simple Sentiment Analysis App",
      "version": "0.9.0",
      "private": true,
      "dependencies": {
        "express": "3.x",
        "sentiment": "0.2.1"
      }
    }
  2. 使用 npm update 命令告诉 Node.js 获取这个新模块。(备注:文档暗示 npm install 应该已经挑选了这个新依赖项,但我没有看到此行为。)
  3. 需要新的 sentiment 模块:
    var sentiment = require("sentiment");
  4. 创建另一个路由来试验 sentiment 模块:
    清单 4. 情绪分析应用程序接口代码
    app.get('/testSentiment',
        function (req, res) {
            var response = "<HEAD>" +
                "<title>Twitter Sentiment Analysis</title>\n" +
                "</HEAD>\n" +
                "<BODY>\n" +
                "<P>\n" +
                "Welcome to the Twitter Sentiment Analysis app.  " +   
                "What phrase would you like to analzye?\n" +                
                "</P>\n" +
                "<FORM action=\"/testSentiment\" method=\"get\">\n" +
                "<P>\n" +
                "Enter a phrase to evaluate: <INPUT type=\"text\" name=\"phrase\"><BR>\n" +
                "<INPUT type=\"submit\" value=\"Send\">\n" +
                "</P>\n" +
                "</FORM>\n" +
                "</BODY>";
            var phrase = req.query.phrase;
            if (!phrase) {
                res.send(response);
            } else {
                sentiment(phrase, function (err, result) {
                    response = 'sentiment(' + phrase + ') === ' + result.score;
                    res.send(response);
                });
            }
        });

    我为这个新函数的超级简单性向 Web 架构师和设计人员道歉。我承诺稍后将会执行一些更加智能的操作。至于现在,我们会创建一个表单,以便输入一个短语,然后用 sentiment 提供的评级作为响应。重要的函数调用是 sentiment(phrase, function)。本着 Node.js 的精神,情绪库是异步的,所以分析结果由一个回调函数处理。

  5. 重新启动该应用程序并在浏览器中打开 http://localhost:3000/testSentiment
图 5. 情绪分析应用程序的用户界面
该屏幕截图显示在浏览器中打开了 localhost:3000/testSentiment

哇哈à,一个难以置信的情绪分析用户界面!

对示例情绪评分

以下是来自我们的情绪分析应用程序的一些假想结果:

表 1. 分析 “Node.js” 的假想结果
情绪评分解释
Node.js is cool, I love it4非常正面的情绪
Node.js is uncool, I hate it-3非常负面的情绪
Mi piace Node.js. Node.js é bellissima0未检测到情绪。sentiment 仅有一个英文词典。
Node.js is not cool, I do not love it4非常正面,与第一个示例同分。sentiment 不懂语法或否定。

您可看到此方法的局限性,那就是 sentiment 模块仅拥有一个英文词典,而且不懂语法或否定。不过,它对于了解大多数 tweet 的主旨可能已经足够用了。


第 3 步. 将应用程序连接到 Twitter

该应用程序的另一个重要组件是与 Twitter 的连接,这样它才能获取一个 tweet 流,以便对它进行分析。

Twitter 的 Stream 接口 非常适合观察情绪趋势,因为它允许访问一段时间以来针对某个主题的所有 Twitter 内容。

我们的应用程序仅处理公共 Twitter 流,所以 Twitter 的 Application-only Authentication 模式已经足够用。这种简化的 OAuth 交换不需要用户登录或同意提示。使用此方法不需要一组特定于应用程序的 OAuth 密钥,它们已编码到应用程序中。有关的更多信息,请参阅 Twitter Stream API

  1. 使用 ntwitter 模块(它提供了 Twitter API 的一个 Node.js 接口)请求一个提及一个或多个关键词的公共 tweet 流。
  2. 通过将它注册在您的 Twitter 开发人员帐户下来获取一组密钥。转到 Twitter “My Applications” 页面,创建和管理该应用程序。
  3. 向您的应用程序添加两个函数,以测试与 Twitter 的连接。首先使用 ntwitter 和 OAuth 密钥构建一个 twitter 对象,然后执行一次简单调用来验证这些凭据。
    清单 5. 测试您的 Twitter 连接
    // Sample keys for demo and article - you must get your own keys if you clone this application!
    // Create your own app at: https://dev.twitter.com/apps
    var tweeter = new twitter({
        consumer_key: 'your',
        consumer_secret: 'keys',
        access_token_key: ‘go',
        access_token_secret: 'here'
    });
    
    app.get('/twitterCheck', function (req, res) {
        tweeter.verifyCredentials(function (error, data) {
            res.send("Hello, " + data.name + ".  I am in your twitters.");
        });
    });
  4. 重新启动应用程序并访问 /twitterCheck,以查看与 Twitter 的连接和登录是否有效:
    图 6. 测试与 Twitter 的连接
    测试与 Twitter 的连接

    请注意,它将我识别为连接的应用程序的所有者。

  5. 现在与 Twitter 的连接已建立,可添加一个函数,在 Twitter 上监视一个或多个短语。ntwitter 提供了一个完成此任务的非常简单的方法:
    1. 调用 stream() 并将传递要监视的短语。
    2. 使用一个回调函数处理到达的 tweet。

      Twitter Stream API 允许应用程序打开一个流并不断拉取到达的数据。这个函数非常适合 Node.js 应用程序,因为在处理一个流时,它可以保持这个流在服务器上处于打开状态,并更新计数器和计算情绪的平均值。

    3. 创建一个简单界面来设置要监视的短语,并显示传入的结果。更加复杂的应用程序可将 tweet 存储到一个数据库中,以执行更复杂的处理。

清单 6 给出了打开一个流和记录 tweet 抽样的代码的重要部分:

清单 6. 打开一个流并记录 tweet
app.get('/watchTwitter', function (req, res) {
    var stream;
    var testTweetCount = 0;
    var phrase = 'bieber';
    tweeter.verifyCredentials(function (error, data) {
        if (error) {
            res.send("Error connecting to Twitter: " + error);
        }
        stream = tweeter.stream('statuses/filter', {
            'track': phrase
        }, function (stream) {
            res.send("Monitoring Twitter for \'" + phrase + "\'...  Logging Twitter traffic.");
            stream.on('data', function (data) {
                testTweetCount++;
                // Update the console every 50 analyzed tweets
                if (testTweetCount % 50 === 0) {
                    console.log("Tweet #" + testTweetCount + ":  " + data.text);
                }
            });
        });
    });
});

第 4 步. 将各部分组合起来

好的,现在我们已经拥有了完成您的应用层所需的所有部分:

  • 一个提供各种页面的基本的 Express 应用程序
  • 一个评估文本情绪的情绪分析函数
  • 一个提供 tweet 来源供分析的 Twitter 连接

现在我们需要将它们组合起来,执行有意义的操作。完成的应用程序将提示用户输入一个短语,调用 Twitter 来打开一个过滤该短语的流,分析每个匹配的 tweet 的情绪,并创建一个页面来不断监视情绪。

我们将用户界面设置得非常简单,清单 7 显示了完整的应用程序,它完全遵循了保守的 Struts 风格:

清单 7. 完整的应用程序
var tweetCount = 0; 
var tweetTotalSentiment = 0; 
var monitoringPhrase; 

function resetMonitoring() { 
    monitoringPhrase = ""; 
} 

function beginMonitoring(phrase) { 
    var stream; 
    // cleanup if we're re-setting the monitoring 
    if (monitoringPhrase) { 
        resetMonitoring(); 
    } 
    monitoringPhrase = phrase; 
    tweetCount = 0;
    tweetTotalSentiment = 0;
    tweeter.verifyCredentials(function (error, data) {
        if (error) {
            return "Error connecting to Twitter: " + error;
        } else {
            stream = tweeter.stream('statuses/filter', {
                'track': monitoringPhrase
            }, function (stream) {
                console.log("Monitoring Twitter for " + monitoringPhrase);
                stream.on('data', function (data) {
                    // only evaluate the sentiment of English-language tweets
                    if (data.lang === 'en') {
                        sentiment(data.text, function (err, result) {
                            tweetCount++;
                            tweetTotalSentiment += result.score;
                        });
                    }
                });
            });
            return stream;
        }
    });
}

function sentimentImage() {
    var avg = tweetTotalSentiment / tweetCount;
    if (avg > 0.5) { // happy
        return "/images/excited.png";
    }
    if (avg < -0.5) { // angry
        return "/images/angry.png";
    }
    // neutral
    return "/images/content.png";
}

app.get('/', 
    function (req, res) { 
        var welcomeResponse = "<HEAD>" + 
            "<title>Twitter Sentiment Analysis</title>\n" + 
            "</HEAD>\n" + 
            "<BODY>\n" + 
            "<P>\n" + 
            "Welcome to the Twitter Sentiment Analysis app.  What would you like to monitor?\n" + 
            "</P>\n" + 
            "<FORM action=\"/monitor\" method=\"get\">\n" + 
            "<P>\n" + 
            "<INPUT type=\"text\" name=\"phrase\"><BR>\n" + 
            "<INPUT type=\"submit\" value=\"Go\">\n" + 
            "</P>\n" + "</FORM>\n" + "</BODY>"; 
        if (!monitoringPhrase) { 
            res.send(welcomeResponse); 
        } else { 
            var monitoringResponse = "<HEAD>" + 
                "<META http-equiv=\"refresh\" content=\"10; URL=http://" + 
                req.headers.host + 
                "/\">\n" + 
                "<title>Twitter Sentiment Analysis</title>\n" + 
                "</HEAD>\n" + 
                "<BODY>\n" + 
                "<P>\n" + 
                "The Twittersphere is feeling<br>\n" + 
                "<IMG align=\"middle\" src=\"" + sentimentImage() + "\"/><br>\n" + 
                "about " + monitoringPhrase + ".<br>" + 
                "Analyzed " + tweetCount + " tweets...<br>" + 
                "</P>\n" + 
                "<A href=\"/reset\">Monitor another phrase</A>\n" + 
                "</BODY>"; 
            res.send(monitoringResponse); 
        } 
    });

我们最后在应用程序的根路径上放入了一些内容,如清单 7 所示。第一次启动时,该应用程序会显示一个欢迎提示符并收集要监视的短语。然后,它会设置监视流并显示一个结果页面。tweeter 的流回调会被更新,以便通过 sentiment 函数传递 tweet 内容,递增 tweet 计数,然后记录情绪。非英语的 tweet 被过滤掉。

出于演示用途,该应用程序使用了 sentimentImage() 函数,该函数返回一个给定情绪值的图像 URL。高兴和抱怨的范围是随意确定的。我发现大多数主题的情绪范围都出奇的小,可能是由于 tweet 的相对简短。您可随意调整这些范围。

那么让我们尝试一下。以下是一些测试运行的结果:

图 7. Twitter 圈对 Justin Bieber 的情绪是正面的
笑脸图标表达了对主题 “Justin Beiber” 的正面情绪和分析的 tweet 数量 (24)
图 8. Twitter 圈对 Syria 的情绪比较矛盾
中性的脸部图标表明对主题 “Syria” 的中性情绪和分析的 tweet 数量 (5)
图 9. Twitter 圈对 NSA、Snowden、Manning、PRISM 的情绪是气愤的
矛盾的脸部图标表达了对 “NSA, Snowden, PRISM” 的愤怒情绪和分析的 tweet 数量 (4)

其他工具考虑因素

在第 1 步中,我展示了如何使用 nodenpm 命令管理和运行应用程序。可使用一个文本编辑器轻松地完成了所有编码。但是,在开发应用程序的过程中,我实际上使用了另外两个工具来简化开发过程。

Project Icap 技术预览 包含用于 Node.js 开发的插件,为 JavaScript 提供了一种基本的语法突出显示功能,还支持启动您的 Node.js 应用程序。这些插件自动重新加载启动的应用程序,为您提供了一种快速迭代的轻松方式。

我最终还希望将该应用程序推送到一个兼容 Cloud Foundry 的 Node.js 运行时环境中,比如 CloudFoundry.com 或 IBM 新推出的 BlueMix 平台。所以最终的应用程序包含该环境需要的一些额外文件:manifest.yml 文件向 Cloud Foundry 运行时描述应用程序和它的资源需求,npm-shrinkwrap.json 文件告诉 Cloud Foundry Node.js 运行时该应用程序应部署哪些模块。


结束语

在使用 Node.js、Express、ntwitter 和 sentiment 开发此应用程序的过程中,我真实地体验到了使用打包为 Node.js 模块的 Twitter 访问和情绪分析等功能有多轻松。很容易看出为什么 Node.js 对开发 Web 和移动应用程序如此流行。

我现在非常想尝试使用 Express 向应用程序添加更加专业的用户界面。我想它还有许多改进的空间。:)

相关主题:
Node.js
JavaScript
社会分析

参考资料

学习

讨论

  • 加入 developerWorks 中文社区。查看开发人员推动的博客、论坛、组和维基,并与其他 developerWorks 用户交流。

条评论

developerWorks: 登录

标有星(*)号的字段是必填字段。


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件

 


在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。

所有提交的信息确保安全。

选择您的昵称



当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

标有星(*)号的字段是必填字段。

(昵称长度在 3 至 31 个字符之间)

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

 


所有提交的信息确保安全。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Web development
ArticleID=953426
ArticleTitle=使用 Node.js、Express、sentiment 和 ntwitter 构建一个情绪分析应用程序
publish-date=11182013