当前位置: 首页 > 后端技术 > Node.js

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

时间:2023-04-03 19:40:27 Node.js

node-feedparser这篇文章是我在学习node-feedparser时写的。上半部分是github上node-feedparser原文的翻译(英文不好,翻译有误请见谅。),还有一些自我解释;实战的后半部分是我结合compressed.js的总结和我的实际使用,现在分享给大家。希望大家指正。文章信息时间/2017-03-09版本号Node.js:v6.10.0node-feedparser:v2.1.0request:v2.79.0iconv-lite:v0.4.15项目地址/https://github.com/danmactoug...DirectoryFeedparser基于Node.js的RSS、Atom、RDF强大解析器如何安装使用feedparser可选参数exampleAPIfeedparser解析后可以得到什么?meta属性列表article属性列表贡献License实战处理数据采集数据编码问题错误捕获FeedparserRSS,Atom,RDF强大的解析器基于Node.js和RDF信息它有几个你在其他feed中不常看到的特性解析器:它可以解析一些相对的URL链接(例如TimBray的“ongoing”feed)并且它可以正确地解析一些XML命名空间(包括那些非常常规的Feed——由一些主要的Feed元素定义的非常规命名空间)第二篇是,通常Feed的XML命名都是一些固定的标签,但是Feedparser也可以对一些非常规的XML进行解析,这就是强大。如何安装npminstallfeedparser用法这个例子可以简单的演示feedparser的基本概念:请注意,在学习基本演示的同时,你还应该学习简化的示例compressed.js文件,这也会让你的工作更全面。varFeedParser=require('feedparser');varrequest=require('request');//需要引入一个获取提要的请求varreq=request('http://somefeedurl.xml')varfeedparser=newFeedParser([options]);req.on('error',function(error){//解决任何请求错误//这是请求包的错误信息});req.on('response',function(res){varstream=this;//这里this是req(请求的请求文件),是流文件类型if(res.statusCode!==200){this.emit('error',newError('Badstatuscode'));}else{stream.pipe(feedparser);}});feedparser.on('error',function(error){//处理feedparser错误//这是feedparser包的错误信息});feedparser.on('readable',function(){//此时已经获取到Feed信息,可以在这里进行操作varstream=this;//这里this是feedparser,也是流文件类型varmeta=this.meta;//注意:这个meta在feedparser的实例中一直可用。//meta其实就是RSS等一些元信息,后面会介绍later.一般来说,Meta信息是重复的varitem;while(item=stream.read()){console.log(item);//在这里输出每一条feed信息。}});feedparser可选参数normalize:设置false使Feedparser的默认值无效。无论提要的形式如何,此参数都可以将其解析为包含RSS2.0格式的正确属性的对象。序列化后的形式如下(只进入第一层)://通过bash输出:属性名:rss:@value:[objectObject]属性名:rss:titlevalue:[objectObject]属性名:rss:link值:[objectObject]属性名:rss:author值:[objectObject]属性名:rss:guid值:[objectObject]属性名:rss:category值:[objectObject]属性名:rss:pubdate值:[objectObject]属性名:rss:comments值:[objectObject]属性名:rss:description值:[objectObject]属性名:meta值:[objectObject]addmeta:设置false使Feedparser默认值失效。将元信息添加到每个提要的文章信息中。我个人建议可以设置为true。一般来说,每个feed的Meta信息都是唯一的,只是文章信息不同而已。只要是第一次获取Meta,只需要文章信息即可。feedurl:提要的URL地址。FeedParser很好地处理了相对url,但是有些提要在使用相对url时没有声明xml:base信息。尽管feedparser非常有效,但是在我们处理feed并尝试处理这些相对url之前,我们仍然不知道feed的url。如果我们找到提要url,我们将返回并处理我们获得的相关url,但这需要一段时间(不会很长)。如果你想确定我们不预处理相对url(或者feedparser不能处理相对url),你应该设置feedurl选项,否则你看不到它~resume_saxerror:设置false使默认值失效的Feedparser。该选项可以在错误中抛出SAXError错误并自动执行后续解析。在我的测试中,SAXErrors并不是很错误,所以打开这个选项通常对你有很大帮助。如果您想完全掌握和处理错误并在任何时候中止解析提要,请尝试此选项。示例请参阅此处的示例。API转换StreamFeedparser是一个流转换器(可以在nodejs官网了解stream),将XML文件转换为Javascript对象。每个可读块都是一个对象,表示提要中的文章信息。发送的itemmeta-解析后称为feed的metaerror-任何时候Feedparser发出错误(包括SAXError、Feedparsererror等)feedparser解析后能得到什么?Feedparser为每个提要解析出元数据和一篇或多篇文章。无论提要的形式如何,元数据和每篇文章都包含符合RSS2.0的流以及规范化的属性。例如,Atom提要有一个meta.description属性,但也有一个meta['atom:subtitle']属性。这个规范化的属性用来为用户提供一个标准化的接口——当你不知道提要的形式,或者搞不清楚不同提要形式之间的差异时,你可以使用这个接口来方便地获取提要信息。但是,当您需要原始信息时,它仍然会保留给您使用。此外,Feedparser还提供了一些流行的命名空间扩展,例如itunes、media、feedburner和pheedo扩展。示例:如果一篇feed文章同时包含itunes:image或media:thumbnail,那么这两个的url地址将保存在文章的image.url属性中。所有属性都被初始化并设置为null(空数组或空对象将具有适当的属性)。这可以为您节省大量检查属性是否为undefined的时间,例如,在使用jade模板时。否则,所有属性(包括名称空间)都将小写(“xmlUrl”和“pubDate”仍然提供向后兼容性)。“Easytouse”取代了“native”——希望大家不用担心骆驼拼法。如果您将normalize设置为true,那么meta和文章标题以及描述属性都将去除HTML标签。如果您需要这些HTML元素,您可以从meta['atom:subtitle']['#']属性中获取它们。meta属性列表titledescriptionlink(网站链接)xmlurldate(最近日期)pubdate(原始发布日期)authorlanguageimage(包含url和title属性的对象)favicon(链接到favicon-仅为Atom提要提供)copyrightgeneratorcategories(字符串数组)article属性列表titledescription(通常是完整的标题内容)summary(通常是文章的摘录)linkoriglinkpermalinkdatepubdateauthorguidcommentsimagecategoriessourceenclosuresmetacontributionsViewallcodehere->contributors.License(TheMITLicense)实际上是处理数据的两种信息,一种是标准化的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封装*/newPromise((resolve,reject)=>{//这里是一些请求操作代码,暂时省略feedparser.on('readable',function(){varitem;while(item=this.read()){resolve(item);}}).then((result)=>{//这里可以使用then继续操作console.log(result.title);//也可以返回一个Promise对象,在别处调用这个Promise。//但是需要注意的是,在调用Promise的地方也需要异步编程returnresult;}).catch((err)=>{console.log(err);});编码问题爬取非英文网页时,总会遇到编码问题,中文也不例外。比如新浪新闻的编码是“utf-8”,而腾讯新闻的编码是“gb3212”。feedparser虽然强大,但是它并不负责解决这些问题。这时候就需要引入iconv-lite来解决编码问题。varurl="http://www.example.xml";varreq=request(url);varfeedparser=FeedParser();varencode='utf-8';req.on('response',function(res){console.log(res.statusCode);//200console.log(res.headers['content-type']);//'image/png'}).pipe(iconv.decodeStream(encode))//在iconv-lite中可以直接调用.pipe(feedparser);因为request和feedparser之间是通过stream进行通信的,而iconv-lite恰好有Stream的API接口,直接调用即可。如果你有兴趣或者有需要,也可以查看iconv-lite的官方文档,看看其他的方法。Errorcatching在整个抓取feed的过程中,会遇到很多错误,如何处理这些错误?这里参考官方文档中提到的compressed.js中的方法,将所有的错误处理写成一个函数,然后在各个事件监听的地方调用错误处理函数来完成。//错误处理函数:functiondone(err){if(err){console.log(err,err.stack);返回进程.exit(1);}process.exit();}//事件监控调用完成//...省略req.on('error',done);//...省略feedparser.on('error',done);feedparser.on('结束',完成);feedparser.on('可读',function(){//...省略});