突破进取务实创新,自信源自实力

语言大同小异,精通多实践,快速学习+编程习惯;思想算法设计,通用真功夫非一朝一夕,夯实基础+智慧,善于利用语言工具和巨人的肩膀。Step By Step...

ruby way之处理RSS和Atom

1 rss 标准库 

RSS 是基于xml的,因此你能简单的将它作为一个xml来进行解析.可是,事实上他有一个更高级别的专有的解析器来解析他.此外RSS的标准也很混乱。 

他有很多不便,就是标准的版本的不兼容,RSS有0.9, 1.0, 和2.0的版本.RSS的版本,就像制造热狗,就是一些除非你一定要知道,否则你不想要知道的细节. 

ruby有一个标准RSS库,它包含0.9,1.0和2.0版本标准.不同的版本之间尽可能做到了无缝处理.如果你没有指定版本,这个库他会自己尽可能地检测版本. 

看下面的例子,这里我们是从http://marsdrive.com 得到feed: 

Java代码  收藏代码
  1. require 'rss'  
  2. require 'open-uri'  
  3.   
  4. URL = "http://www.marstoday.com/rss/mars.xml"  
  5. open(URL) do |h|  
  6.   resp = h.read  
  7.   result = RSS::Parser.parse(resp,false)  
  8.   puts "Channel: #{result.channel.title}"  
  9.   result.items.each_with_index do |item,i|  
  10.     i += 1  
  11.     puts "#{i}  #{item.title}"  
  12.   end  
  13. end  


这个程序很简单,一直要看一下mars.xml的结构就很清晰了. 

下面我们来创建一个RSS Feed 

Java代码  收藏代码
  1. require 'rss'  
  2.   
  3. feed = RSS::Rss.new("2.0")  
  4.   
  5. chan = RSS::Rss::Channel.new  
  6. chan.description = "Feed Your Head"  
  7. chan.link = "http://nosuchplace.org/home/"  
  8.   
  9. img = RSS::Rss::Channel::Image.new  
  10. img.url = "http://nosuchplace.org/images/headshot.jpg"  
  11. img.title = "Y.T."  
  12. img.link = chan.link  
  13.   
  14. chan.image = img  
  15. feed.channel = chan  
  16.   
  17. i1 = RSS::Rss::Channel::Item.new  
  18. i1.title = "Once again, here we are"  
  19. i1.link = "http://nosuchplace.org/articles/once_again/"  
  20. i1.description = "Don't you feel more like you do now than usual?"  
  21.   
  22. i2 = RSS::Rss::Channel::Item.new  
  23. i2.title = "So long, and thanks for all the fiche"  
  24. i2.link = "http://nosuchplace.org/articles/so_long_and_thanks/"  
  25. i2.description = "I really miss the days of microfilm..."  
  26.   
  27. i3 = RSS::Rss::Channel::Item.new  
  28. i3.title = "One hand clapping"  
  29. i3.link = "http://nosuchplace.org/articles/one_hand_clapping/"  
  30. i3.description = "Yesterday I went to an amputee convention..."  
  31.   
  32. feed.channel.items << i1 << i2 << i3  
  33.   
  34. puts feed  


这个代码也很简单,就是先创建了一个空的RSS 2.0 feed ,然后给他的一些节点开始赋值. 

这里要注意我们想要把一些Item对象付给feed.channel.items时,我们不能使用 
Java代码  收藏代码
  1. feed.channel.items = [i1,i2,i3]  
这样的代码,我们只能使用items[0] = i1 这样的代码.或者用我们上面代码中的使用<<方法. 

很多人可能更喜欢用Atom,比起RSS,可是rss库不支持Atom,但是非标准的feedtools 库支持Atom.我们下面就要介绍它. 

2 feedtools Library 

feedtools他以无缝的方式工作在Atom和RSS中,它存储所有的feeds作为一个共有的内部的格式.并且它有它自己的url处理代码,因此你不需要显示的使用net/http 或者open-uri. 

下面这段代码是用feedtools来处理前面的那个例子: 

Java代码  收藏代码
  1. require "feed_tools"  
  2.   
  3. URL = "http://www.marstoday.com/rss/mars.xml"  
  4. feed = FeedTools::Feed.open(URL)  
  5. puts "Description: #{feed.title}\n"  
  6.   
  7. feed.entries.each_with_index {|x,i| puts "#{i+1} #{x.title}" }  
  8.    


这段代码比起上面的那段代码更为简洁和清晰.可以看到这里并没有显式的channel 方法,可是你却可以直接在feed对象上调用title等方法,这是因为一个feed就是一个channel. 

下面的是存取Atom的例子: 

Java代码  收藏代码
  1. require "feed_tools"  
  2.   
  3. URL = "http://www.atomenabled.org/atom.xml"  
  4. feed = FeedTools::Feed.open(URL)  
  5. puts "Description: #{feed.title}\n"  
  6.   
  7. feed.entries.each_with_index {|x,i| puts "#{i+1}  #{x.title}" }  


注意,对比一下这两个代码,不同点只有一个,那就是URL的不同,这就说明我们处理feeds时,不需要知道他被存储为哪种格式. 

现在让我们加下面的代码到上面的例子中: 

Java代码  收藏代码
  1. str = feed.build_xml("rss",2.0)  
  2. puts str  


我们所做的就是将Atom feed 转换为RSS2.0的feed.你也可以转换成0.9或者1.0版本.因此我们能读一个RSS的feed然后制造出一个Atom的feed.这个就是这个库的强大之处. 

这里要强调一下,我们上面的例子都只是一个小测试,如果你要真正做一个应用程序的话,你要注意处理你的缓存. 


ruby 1.8.7 + rails 2.1.0

打开 http://www.google.cn/finance?q=600001 这个网址 可以看到 谷歌财经的 右侧 有个新闻区。。。这个新闻区就是从别的地方抓取来的
截图:


现在我们也来仿照它来实现一个,首先rails解析rss有两种方式,一种是用封装好的类库,一种是用原始的解析xml的方式,或者利用别人封装好的库 例如feedtools, rubyrss 等
用类库的方法:
    require 'rss/2.0'
    require 'open-uri'
    url = "http://news.google.cn/news?pz=1&ned=ccn&hl=zh-CN&topic=b&output=rss"
    @feed = RSS::Parser.parse(open(url).read, false)
    @feed.items.each do |item| 
      puts item.title
      puts item.link
      puts  item.description
    end

解析xml的方法:
在lib下建立一个RssParser的类,这样在任何地方都可以调用
class RssParser
  require 'rexml/document'
  def self.run(url)
    xml = REXML::Document.new Net::HTTP.get(URI.parse(url))
    data = {
      :title    => xml.root.elements['channel/title'].text,
      :home_url => xml.root.elements['channel/link'].text,
      :rss_url  => url,
      :items    => []
    }
    xml.elements.each '//item' do |item|
      new_items = {} and item.elements.each do |e|
        new_items[e.name.gsub(/^dc:(\w)/,"\1").to_sym] = e.text
      end
      data[:items] << new_items
    end
    data
  end
end

action中使用:
  def test
    feed = RssParser.run("http://news.google.cn/news?pz=1&ned=ccn&hl=zh-CN&topic=b&output=rss")
    feed1 = feed[:items][0]
    feed2 = feed[:items][0]
    feed3 = feed[:items][0]
    # combine the feeds into an array
    @feeds = [feed1, feed2, feed3]
    # parse the pubDate strings into a DateTime object
    @feeds.each {|x| x[:pubDate] = DateTime.parse(x[:pubDate].to_s)}
    # iterate through each feed, sorting by pubDate
    @feeds.sort! {|a,b| a[:pubDate] <=> b[:pubDate]}
    # reverse the array to sort by descending pubDate
    @feeds.reverse!
    @feeds.each do |feed|
      puts feed[:title]
      puts feed[:link]
      puts feed[:pubDate]
    end
  end

那么上面的title link description 是从哪里来的呢。。。这个是rss2.0的xml结构,一般情况下是这样的:
<?xml version="1.0" encoding="utf-8"?>

<rss version="2.0">

<channel>

         <title>Example Feed</title>

<description>Insert witty or insightful remark here</description>

<link>http://example.org/</link>

<lastBuildDate>Sat, 13 Dec 2003 18:30:02 GMT</lastBuildDate>

<managingEditor>johndoe@example.com (John Doe)</managingEditor>

<item>

<title>Atom-Powered Robots Run Amok</title>

<link>http://example.org/2003/12/13/atom03</link>

<guid isPermaLink="false">urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</guid>

<pubDate>Sat, 13 Dec 2003 18:30:02 GMT</pubDate>

<description>Some text.</description>

</item>

</channel>

</rss>



或者你可以查看rss的页面源代码,或者puts下  @feed = RSS::Parser.parse(open(url).read, false)的结果都可以看到上面的这中xml文档结构



好,下面我们开始实现上面图的新闻:

我们可以把这个部分放在partial里,所以只需要helper和partial文件

helper:

def feed_collection(param)

require 'rss/2.0'

require 'open-uri'

# from news.google.cn

urlhot = "http://news.google.cn/news?pz=1&ned=ccn&hl=zh-CN&topic=b&output=rss"

urlfinance = "http://news.google.cn/news?pz=1&ned=ccn&hl=zh-CN&topic=ecn&output=rss"

urlfund = "http://news.google.cn/news?pz=1&ned=ccn&hl=zh-CN&topic=stc&output=rss"

urlfinancing = "http://news.google.cn/news?pz=1&ned=ccn&hl=zh-CN&topic=pf&output=rss"

case param

when 'hot'

RSS::Parser.parse(open(urlhot).read, false)

when 'finance'

RSS::Parser.parse(open(urlfinance).read, false)

when 'fund'

RSS::Parser.parse(open(urlfund).read, false)

when 'financing'

RSS::Parser.parse(open(urlfinancing).read, false)

end   

end



def feed_link(param)

require 'cgi'

CGI.unescape(param.slice(/(http%).*(&)/)).gsub(/&/,'')  if param # 把十六进制路径 例如http%3A2F之类的转化为 字符

end



def feed_title(param)

param.slice(/.*(-)/).gsub(/-/,"") if param #截取需要的title

end



def feed_from(param)

param.slice(/( - ).*/).from(2) if param # 截取需要的部分

end





partial: _feednews.erb.html

<div class="slides">        

<div><%= render :partial => 'shared/feednews_item',:collection => feed_collection("hot").items %></div>

<div><%= render :partial => 'shared/feednews_item',:collection => feed_collection('finance').items %></div>

<div><%= render :partial => 'shared/feednews_item',:collection => feed_collection('fund').items %></div>

<div><%= render :partial => 'shared/feednews_item',:collection => feed_collection('financing').items %></div>

</div>



主义这里参考了 jquery的loopslider 插件(幻灯片) 加载显示的只是第一个div部分,可以参考:

http://github.com/nathansearles/loopedSlider/tree/master



partial: _feednews_item.html.erb

<ul>

<% unless feednews_item.nil? %>

<li  class="news"><a  href="<%= feed_link(feednews_item.link) %>" target="_blank"><%=  feed_title(feednews_item.title) %></a>



<span class="grey small"><span> <%= feed_from(feednews_item.title) %></span> — <span><%= feednews_item.pubDate.to_date %></span></span></li>

<% end %>

</ul>



okay....已经成功了,我实现的截图:



ref:
http://www.rubycentral.com/book/ref_c_string.html
http://www.javaeye.com/topic/60620
http://www.troubleshooters.com/codecorn/ruby/basictutorial.htm#_Regular_Expressions
http://paranimage.com/15-jquery-slideshow-plugins/#respond
http://hi.baidu.com/todayz/blog/item/83c1b219d966fd4142a9ad5f.html
http://dennis-zane.javaeye.com/blog/57538
http://sporkmonger.com/projects/feedtools/
http://rubyrss.com/
http://rubyrss.com/
http://www.superwick.com/archives/2007/06/09/rss-feed-parsing-in-ruby-on-rails/
http://www.ruby-forum.com/topic/144447



阅读更多
文章标签: ruby rss
个人分类: RUBY编程
想对作者说点什么? 我来说一句

THE RUBY WAY(中文版)(第二版)pdf

2017年10月15日 29.98MB 下载

The Ruby Way(处理文件和目录)

2008年12月02日 399KB 下载

北大青鸟RSS新闻阅读器

2010年05月07日 566KB 下载

RSS新闻阅器,RSS新闻阅器

2011年06月05日 898B 下载

vs2005 订阅 rss atom

2009年01月07日 1.11MB 下载

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭