feedparser学习与实战——基于Node.js的Feed解析器

node-feedparser

这篇文章是我学习node-feedparser的时候所写的,前半部分是翻译了node-feedparser在github上的原文(英语不好,如果翻译有误,还请见谅。),当中也夹杂了一些自己解释;后半部分的实战是我结合 compressed.js ,同时自己在实际运用中的小结,现在拿出来和大家分享,希望大家给予指正。

文章信息

目录

  • Feedparser 基于Node.js的RSS,Atom,RDF强劲解析器

  • 如何安装

  • 用法

    • feedparser可选参数

  • 例子

  • API

  • feedparser解析后能得到什么?

    • meta属性列表

    • article属性列表

  • 贡献

  • License

  • 实战

    • 处理数据

    • 取得数据

    • 编码问题

    • 错误捕捉

Feedparser 基于Node.js的RSS,Atom,RDF强劲解析器

Feedparser是一个基于基于Node.js的强劲解析器,可以解析包括RSS,Atom和RDF信息

它有一对特性是你在其他的Feed解析器中不常见的:

  1. 它可以解析一些相对URL链接(例如Tim Bray's "ongoing"这个Feed)

  2. 它可以正确地解析一些XML命名空间(包含那些非常规的Feed——用主要的一些Feed元素来定义的非常规命名空间)

说明:对第二条的理解是,通常Feed的XML命名是固定的一些标签,但是Feedparser同样可以对一些非常规的XML进行解析,这就是强大之处。

如何安装


npm install feedparser

用法

这个例子能简要地示范feedparser的基本概念:

请注意在学习基本的示范的同时,也要学习简化的范例compressed.js文件,这样也能够让你更全面地开展工作。


var FeedParser = require('feedparser');
var request = require('request'); // 需要引入一个request,用于抓取Feed

var req = request('http://somefeedurl.xml')
var feedparser = new FeedParser([options]);

req.on('error', function (error) {
  // 解决任何的request请求错误
  // 这个是request包的错误提示
});

req.on('response', function (res) {
  var stream = this; // 这里的this是req(所请求request文件),是stream文件类型

  if (res.statusCode !== 200) {
    this.emit('error', new Error('Bad status code'));
  }
  else {
    stream.pipe(feedparser);
  }
});

feedparser.on('error', function (error) {
  // 处理feedparser的错误
  // 这个是feedparser包的错误提示
});

feedparser.on('readable', function () {
  // 此时已经获取到Feed信息,在这里可以进行你的操作了
  var stream = this; // 这里的this是feedparser, 也是stream文件类型
  var meta = this.meta; // 注意:这个meta是在feedparser的实例中一直可以获得。
  //Meta其实是RSS等一些的元信息,在后面会介绍到,一般来说Meta信息都是重复的。
  var item;

  while (item = stream.read()) {
    console.log(item);
    //在这里输出每一条Feed信息。
  }
});

feedparser可选参数

  • normalize:设置false让Feedparser的默认值失效。无论这个Feed的形式,这个参数都能将其解析成一个包含RSS2.0格式,正确属性的对象。序列化后的形式如以下所示(只进入第一层):

//通过bash输出:

属性名:rss:@  值:[object Object]
属性名:rss:title  值:[object Object]
属性名:rss:link  值:[object Object]
属性名:rss:author  值:[object Object]
属性名:rss:guid  值:[object Object]
属性名:rss:category  值:[object Object]
属性名:rss:pubdate  值:[object Object]
属性名:rss:comments  值:[object Object]
属性名:rss:description  值:[object Object]
属性名:meta  值:[object Object]
  • addmeta:设置false让Feedparser的默认值失效。让每一个Feed的article信息都加入Meta信息。个人建议可以设置为true,一般来说,每个Feed的Meta信息都是唯一的,而article信息不同,只要第一次获取Meta后,就可以只需要article信息。

  • feedurl:Feed的URL地址。FeedParser能非常优秀地处理相对url,但是一些Feed在使用相对url时,并不声明xml:base信息。尽管feedparser非常有效,但是在我们处理feed和尝试着处理这些相对url之前,我们仍然不能知道feed的url。如果我们发现了feed的url,我们将会返回并处理那些我们已经得到的相对url,但这将会消耗一段时间(并非很长)。如果你想要确信我们不对相对url进行预处理(或者feedparser无法处理相对url),你应该设置feedurl选项,否则,你就当没看见过它吧~

  • resume_saxerror:设置false让Feedparser的默认值失效。这个选项能够抛出error中的SAXError错误,并自动进行后续的解析。在我的测试中,SAXErrors并不常错误,所以开启这个选项通常对你很有帮助。如果你想要完全掌握和处理错误,并在任意点中止解析feed的话,可以尝试用这个选项。

例子

在这里查看例子 examples

API

转换 Stream

Feedparser是一个stream转换器(关于stream你可以在nodejs官网阅读),从XML文件转换为Javascript的objects对象。

每一个可读的区块都是一个对象,这个对象代表feed中的article信息。

发出的项目

  • meta - 被解析后,称作feed的 meta

  • error - 任何时候Feedparser发出的错误(包括SAXError, Feedparser error等)

feedparser解析后能得到什么?

Feedparser对每一个Feed都会解析出 meta 和一个或更多的 articles

不论Feed的形式如何, meta 和每一个 article 都包含一个RSS2.0规范同时加上规范化后的属性的信息流。举个例子,一个Atom feed会有一个 meta.description 属性,但是同样会有一个 meta['atom:subtitle'] 属性。

这个规范化后的属性是用于向用户提供一个规范的接口——当你不知道feed的形式,或者搞不清不同feed形式之间的差异时,用这个接口就可以方便获取feed信息。不过当你需要原始信息的时候会依然会保留给你使用。此外,Feedparser还提供了一些大众化的命名空间扩展,例如 itunes , media , feedburnerpheedo 这些扩展。举例:如果一个feed的article同时包含了 itunes:imagemedia:thumbnail ,那么这两个的url地址都会保存到article的 image.url 属性中。

所有的属性都会进行初始化,设置为 null (空数组或者空对象都会有恰当的属性)。这个能够节省你很多时间来检查属性是否为 undefined ,例如,当你使用jade模板的时候。

除此之外,所有的属性(包含命名空间)都使用小写字母("xmlUrl" and
"pubDate"仍然提供向下兼容)。“好用”取代了“原生”——衷心希望你能不必为骆驼拼写法而烦恼。

如果你设置normalize为true,那么 metaarticletitledescription 属性都会将HTML标签剥离。如果你需要这些HTML元素,你可以从 meta['atom:subtitle']['#'] 这个属性取得。

meta属性列表

  • title

  • description

  • link (网站链接)

  • xmlurl

  • date (最近的日期)

  • pubdate (原始出版日期)

  • author

  • language

  • image (一个对象,包含 urltitle 属性)

  • favicon (favicon的链接——只提供给Atom feeds)

  • copyright

  • generator

  • categories (一个字符串数组)

article属性列表

  • title

  • description (通常是完整的标题内容)

  • summary (通常是文章摘录)

  • link

  • origlink

  • permalink

  • date

  • pubdate

  • author

  • guid

  • comments

  • image

  • categories

  • source

  • enclosures

  • meta

贡献

在这里查看所有代码 -> contributors

License

(The MIT License)

实战

处理数据

feedparser.on('readable', function() {
  var item;
  while (item = this.read()) {
    //一般我们在这里获取数据,在上面提到的,feedparser一共会输出两种信息,一种是规范化后的RSS2.0,另一种是原有的。
    //原有信息的获取:(推荐这种)
    console.log(item.meta.title);
    console.log(item.title);
    //RSS2.0信息的获取:
    console.log(item['meta']['rss:title']['#']);
    console.log(item['rss:title']['#']);
  }
});

需要注意的是你无法通过return将上述的数据从函数中取出,也无法通过在外定义变量,在内赋值取出。因为这里用到了异步编程的事件监听,所有的动作都是异步操作,如果通过上述两个办法取出的值都是undefined。那么如何取出这些数据?这里有两个办法:

取得数据

因为feedparser使用的是异步编程的办法,所以无法通过常规方法取出值,不过仍然有以下两种办法:

  • 直接在函数中进行操作

  • 使用Promise封装

/*
 *  在函数中直接进行操作不再演示
 *  这里主要演示Promise封装
 */

new Promise((resolve, reject)=>{
    //这里是一些request操作代码,暂时省略

    feedparser.on('readable', function() {
      var item;
      while (item = this.read()) {
        resolve(item);
      }
}).then((result)=>{
  //在这里可以用then继续操作
  console.log(result.title);
  //也可以return一个Promise对象,并在其他地方调用这个Promise。
  //但需要注意,在调用Promise的地方也需要异步编程
  return result;
}).catch((err)=>{
  console.log(err);
});

编码问题

在抓取非英文网页时,总会遇到编码问题,中文也不例外。比如新浪新闻的编码是"utf-8",但是腾讯新闻的编码是"gb3212"。feedparser虽然强大,但不负责解决这些问题,这个时候需要我们引入 iconv-lite ,来解决编码问题。

var url = "http://www.example.xml";
var req = request(url);
var feedparser = FeedParser();
var encode = 'utf-8';

req.on('response', function (res) {
      console.log(res.statusCode); // 200
      console.log(res.headers['content-type']); // 'image/png'
    }).pipe(iconv.decodeStream(encode)) //在iconv-lite可以直接调用
    .pipe(feedparser);

因为 requestfeedparser 之间的通讯是通过stream流的,而 iconv-lite 正好又有对于Stream流的API接口,所以直接调用即可。如果感兴趣或者有需要的同学还可以去查看 iconv-lite官方文档查看其它的方法。

错误捕捉

在整个抓取Feed的过程中,会遇到很多的错误,如何处理这些错误?这里借鉴一下官方文档所提到的 compressed.js 中的方法,它将所有的错误处理写成一个函数,然后在每次事件监听的地方,调用处理错误函数即可完成。

//错误处理函数:
function done(err) {
  if (err) {
    console.log(err, err.stack);
    return process.exit(1);
  }
  process.exit();
}

//事件监听调用done
// ...省略
  req.on('error', done);
  // ...省略
  feedparser.on('error', done);
  feedparser.on('end', done);
  feedparser.on('readable', function() {
    // ...省略
  });
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值