Joseph McCarthy
Java 开发人员
Joseph McCarthy 是一名 Java™ 和 JavaScript 开发人员,在前端和服务器端的应用程序领域中均拥有超过十年的从业经验。在业余时间,他喜欢探索流行服务(如 Facebook、Twitter 和 Google)的公共 API,以增强用户体验。
Twitter 提供了自定义小部件来将 Twitter 提要嵌入到网站上。您可以根据各种来源来创建提要,这些来源包括您自己的推文或收藏、一个 Twitter 列表,或者 Twitter 搜索的结果。在 2006 年 Twitter 刚创立时,小部件可生成多种格式的提要,包括 XML、Atom、JSON 和 RSS。但随着 2012 年 9 月该 API 的 1.1 版发布,除 JSON 外的所有格式都被弃用了。
如果您像我一样,一定特别遗憾没有 RSS 选项。RSS 很有用,因为您可以在邮件客户端、浏览器的提要阅读器或专门的 RSS 阅读器软件中阅读提要。而且 RSS 很容易与 IFTTT.com 上的秘诀相集成来实现自动化。
RSS 爱好者很容易获得帮助。在本教程中,您将创建一段简单的 Node.js 脚本来解析来自 Twitter 小部件的 JSON 提要,并以 RSS 形式返回它。该脚本使用 REST 调用来检索小部件提要,通过 node-elementtree
模块解析该提要,然后从 Express 路线以 RSS 提要形式返回结果。
作为最后一步,您将 RSS 提要部署到 IBM Bluemix,以便用户可以在其浏览器中阅读它或从其他程序订阅它。本教程中使用了一个 Twitter 列表小部件,但您可以对从任何 Twitter 来源创建的小部件应用相同的方法。
运行应用程序
获取代码
在桌面浏览器中,登录到您的 Twitter 帐户。单击页面右上角您的个人照片,从菜单中选择 Lists 。您可以在这里看到现有列表(如果有)和 Create new list 按钮。按照以下链接中的说明为您选择的内容创建一个新列表:
阅读: 使用 Twitter 列表
对于本教程,我创建了一个 Writers 列表,其中包含 Twitter 上我最喜欢的作家:
data-widget-id
值。 从命令行,使用 npm 创建一个新 Node.js 项目:
npm init
对于大部分选项,保持默认值即可。(请注意,在最新的 npm 版本中,项目名称不能包含大写字符。)
request
模块(Node REST 客户端的事实标准)添加到项目中:
npm --save install request
可选的--save
标志可将该模块添加到 package.json 中的项目依赖项中,节省了自行将它添加到该文件的手动步骤。
main
属性值相匹配的名称 — 通常为 index.js。将以下代码添加到 index.js,将 <widget ID>
替换为第 2 步中的小部件 ID 值: var request = require('request'); request.get("http://cdn.syndication.twimg.com/widgets/timelines/<widget ID>", function(err, resp, body) { });所有 Twitter 列表小部件均可从前面代码段中的 REST 端点进行访问:
http://cdn.syndication.twimg.com/widgets/timelines/widget ID
。成功完成 REST 调用后,这个匿名函数的 body
变量将会包含 Twitter 提要。 在接下来的 3 步中,您继续创建 index.js 解析脚本的代码,并在第 6 步将它们结合在一起。
来自 REST 调用的响应是有效的 JSON,但它是明文形式的,所以您需要使用 Node 的内置 JSON 解析器将它转换为 JSON 对象。您的脚本还必须对该对象的 body
属性应用以下更改,然后才能用 node-elementtree
XML 解析器解析它:
/r
和 /n
删除所有换行符或回车字符。 /s
将所有存在多个空格的地方转换为单个空格。 <img>
标记(它们已在 HTML 中正确关闭,但在 XML 中没有正确关闭。) <time>
标记中的空 pubdate
属性(它在 HTML 中是可以接受的,但在 XML 中是无法接受的)。 &.*?;
找到并删除 Unicode 字符,比如 ‎
和 &
。 阅读: JavaScript 中的正则表达式
使用以下代码执行更正:
var json = JSON.parse(body); var list = json.body.replace(/(/r/n|/n|/r)/gm, " ") .replace(//s+/g, " ") .replace(/<img.*?>/gi, "") .replace(/pubdate/gi, "") .replace(/&.*?;/gi, "");
现在该提要是有效的 XML,但它可由 node-elementtree
Node.js 模块解析:
node-elementtree
并将它添加到 package.json 文件:
npm --save install elementtree
var etree = et.parse(list);
title
:RSS 提要标题 link
:与提要相关的网站的 HTML 链接 description
:提要的描述 阅读: RSS 规范
此信息采用以下格式存储在 XML 文档中:<?xml version="1.0" encoding="UTF-8"?> <rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"> <channel> <title>RSS Feed Title</title> <link>RSS Feed Link</link> <description>RSS FEED</description> </channel> </rss>可以使用 XPath 表达式从文档树中检索这些值:
div/h1
上的节点中。 div/h2/a
上的节点的 href
属性中的 Twitter 页面 URL,并将它与 /lists/
路径和列表名称组合在一起,形成列表 URL。 div/p
上 var et = require('elementtree'); var title = etree.findtext('div/h1'); var link = etree.find('div/h2/a').get("href"); var description = etree.findtext('div/p'); var rss = '<?xml version="1.0"?><rss version="2.0" ; rss += '<channel><title>' + title + '</title>'; rss += '<link>' + link + '/lists/' + title + '</link>'; rss += '<description>' + description + ' </description>'; rss += "</channel></rss>";
<ol>
列表中,显示为 <li>
列表项条目。所有列表项都通过 etree.findall()
调用从 div/div/ol/li
路径检索,并显示为一个数组。
您使用每个推文在 rss
字段中创建一个新条目。依据规范,提要中的 RSS 条目必须包含一个标题或描述字段;其他任何字段都不是必填字段。
使用此代码将每个新条目添加到 RSS 字符串:
var tweets = etree.findall('div/div/ol/li'); for (var counter = 0; counter < tweets.length; counter++) { var tweet = tweets[counter]; var tweetTitle = tweet.findtext('div/p').trim(); var author = tweet.findtext('div[@class="timeline-Tweet u-cf js-tweetIdInfo"]/' + 'div[@class="timeline-Tweet-author"]/' + 'div/a/span[@class="TweetAuthor-screenName Identity-screenName"]'); var tweetPermalink = tweet.find('div/div[@class="timeline-Tweet-metadata"]/a') .get('href'); var pubDate = Date.parse(tweet.find('div/div[@class="timeline-Tweet-metadata"]/a/time') .get('datetime')); rss += "<item>"; rss += "<title>" + tweetTitle + "</title>"; rss += "<pubDate>" + new Date(pubDate).toUTCString() + "</pubDate>"; rss += "<guid>" + tweetPermalink + "</guid>"; rss += "<link>" + tweetPermalink + "</link>"; rss += "<description> " + author + ": " + tweetTitle + "</description>"; rss += "</item>"; }
在前面的代码中,使用以下内容构建了每个条目:
div/p
节点的推文文本 div[@class="timeline-Tweet u-cf js-tweetIdInfo"]/div[@class="timeline-Tweet-author"]/ div/a/span[@class="TweetAuthor-screenName Identity-screenName"]
guid
,采用 div/div[@class="timeline-Tweet-metadata"]/a
上的节点的 href
属性的推文 URL pubdate
字段需要采用 RFC-822 格式。JavaScript Date
对象可使用 toUTCString()
方法采用此格式返回日期。您将 div/div[@class="timeline-Tweet-metadata"]/a/time
上的节点的 datetime
属性传递给 Date.parse()
方法,以便返回自 1970 年 1 月 1 日以来的毫秒数。然后使用此值创建一个新的 Date
对象,并调用 toUTCString()
方法获取正确的值。
您可以针对 W3C 提要验证服务 而验证 RSS 字符串。
现在您已准备好配置一个 Express 服务器,以便从一个 Web 服务调用返回 RSS 字符串:
从命令行安装 Express:
npm --save install express
var express = require('express'); app.set('port', process.env.PORT || 3000); http.createServer(app).listen(app.get('port'), function(){ console.log('Express server listening on port ' + app.get('port')); }); app.get('/', function(request, response) { });
res.send(rss);
将完成的 RSS 提要返回给用户。 从命令行启动该服务器:
node index.js
大部分(或许是所有)浏览器都拥有原生的 RSS 阅读器。要在 Chrome 中阅读 RSS 提要,可以安装一个扩展,比如 feedly 。
该服务器在默认请求路径 (/) 上监听请求。您可以在 app.get
调用中配置此路径。
从操作系统命令行,将该存储库克隆到本地:
git clone --no-checkout https://hub.jazz.net/git/<em>username</em>/<em>project name</em><br /> cd <em>project name</em><br /> echo "# readme" >> README.md<br /> git add README.md<br /> git commit -m "first commit"<br /> git push -u origin master<br />
本教程概述了如何通过解析 Twitter 列表小部件的输出来创建 RSS 提要,以及如何通过将提要部署到 Bluemix 来在线公开这些提要。以下是一些进一步开发的建议:
atom:link
元素,将 href
属性设置为提要的 URL,但这不是强制性的。将此元素添加到代码中,将 URL 设置为您部署到 Bluemix 上的代码的值。 相关主题: Node.js Twitter RSS