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:
这个程序很简单,一直要看一下mars.xml的结构就很清晰了.
下面我们来创建一个RSS Feed
这个代码也很简单,就是先创建了一个空的RSS 2.0 feed ,然后给他的一些节点开始赋值.
这里要注意我们想要把一些Item对象付给feed.channel.items时,我们不能使用
这样的代码,我们只能使用items[0] = i1 这样的代码.或者用我们上面代码中的使用<<方法.
很多人可能更喜欢用Atom,比起RSS,可是rss库不支持Atom,但是非标准的feedtools 库支持Atom.我们下面就要介绍它.
2 feedtools Library
feedtools他以无缝的方式工作在Atom和RSS中,它存储所有的feeds作为一个共有的内部的格式.并且它有它自己的url处理代码,因此你不需要显示的使用net/http 或者open-uri.
下面这段代码是用feedtools来处理前面的那个例子:
这段代码比起上面的那段代码更为简洁和清晰.可以看到这里并没有显式的channel 方法,可是你却可以直接在feed对象上调用title等方法,这是因为一个feed就是一个channel.
下面的是存取Atom的例子:
注意,对比一下这两个代码,不同点只有一个,那就是URL的不同,这就说明我们处理feeds时,不需要知道他被存储为哪种格式.
现在让我们加下面的代码到上面的例子中:
我们所做的就是将Atom feed 转换为RSS2.0的feed.你也可以转换成0.9或者1.0版本.因此我们能读一个RSS的feed然后制造出一个Atom的feed.这个就是这个库的强大之处.
打开 http://www.google.cn/finance?q=600001 这个网址 可以看到 谷歌财经的 右侧 有个新闻区。。。这个新闻区就是从别的地方抓取来的
截图:
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
RSS 是基于xml的,因此你能简单的将它作为一个xml来进行解析.可是,事实上他有一个更高级别的专有的解析器来解析他.此外RSS的标准也很混乱。
他有很多不便,就是标准的版本的不兼容,RSS有0.9, 1.0, 和2.0的版本.RSS的版本,就像制造热狗,就是一些除非你一定要知道,否则你不想要知道的细节.
ruby有一个标准RSS库,它包含0.9,1.0和2.0版本标准.不同的版本之间尽可能做到了无缝处理.如果你没有指定版本,这个库他会自己尽可能地检测版本.
看下面的例子,这里我们是从http://marsdrive.com 得到feed:
- require 'rss'
- require 'open-uri'
- URL = "http://www.marstoday.com/rss/mars.xml"
- open(URL) do |h|
- resp = h.read
- result = RSS::Parser.parse(resp,false)
- puts "Channel: #{result.channel.title}"
- result.items.each_with_index do |item,i|
- i += 1
- puts "#{i} #{item.title}"
- end
- end
这个程序很简单,一直要看一下mars.xml的结构就很清晰了.
下面我们来创建一个RSS Feed
- require 'rss'
- feed = RSS::Rss.new("2.0")
- chan = RSS::Rss::Channel.new
- chan.description = "Feed Your Head"
- chan.link = "http://nosuchplace.org/home/"
- img = RSS::Rss::Channel::Image.new
- img.url = "http://nosuchplace.org/images/headshot.jpg"
- img.title = "Y.T."
- img.link = chan.link
- chan.image = img
- feed.channel = chan
- i1 = RSS::Rss::Channel::Item.new
- i1.title = "Once again, here we are"
- i1.link = "http://nosuchplace.org/articles/once_again/"
- i1.description = "Don't you feel more like you do now than usual?"
- i2 = RSS::Rss::Channel::Item.new
- i2.title = "So long, and thanks for all the fiche"
- i2.link = "http://nosuchplace.org/articles/so_long_and_thanks/"
- i2.description = "I really miss the days of microfilm..."
- i3 = RSS::Rss::Channel::Item.new
- i3.title = "One hand clapping"
- i3.link = "http://nosuchplace.org/articles/one_hand_clapping/"
- i3.description = "Yesterday I went to an amputee convention..."
- feed.channel.items << i1 << i2 << i3
- puts feed
这个代码也很简单,就是先创建了一个空的RSS 2.0 feed ,然后给他的一些节点开始赋值.
这里要注意我们想要把一些Item对象付给feed.channel.items时,我们不能使用
- feed.channel.items = [i1,i2,i3]
很多人可能更喜欢用Atom,比起RSS,可是rss库不支持Atom,但是非标准的feedtools 库支持Atom.我们下面就要介绍它.
2 feedtools Library
feedtools他以无缝的方式工作在Atom和RSS中,它存储所有的feeds作为一个共有的内部的格式.并且它有它自己的url处理代码,因此你不需要显示的使用net/http 或者open-uri.
下面这段代码是用feedtools来处理前面的那个例子:
- require "feed_tools"
- URL = "http://www.marstoday.com/rss/mars.xml"
- feed = FeedTools::Feed.open(URL)
- puts "Description: #{feed.title}\n"
- feed.entries.each_with_index {|x,i| puts "#{i+1} #{x.title}" }
这段代码比起上面的那段代码更为简洁和清晰.可以看到这里并没有显式的channel 方法,可是你却可以直接在feed对象上调用title等方法,这是因为一个feed就是一个channel.
下面的是存取Atom的例子:
- require "feed_tools"
- URL = "http://www.atomenabled.org/atom.xml"
- feed = FeedTools::Feed.open(URL)
- puts "Description: #{feed.title}\n"
- feed.entries.each_with_index {|x,i| puts "#{i+1} #{x.title}" }
注意,对比一下这两个代码,不同点只有一个,那就是URL的不同,这就说明我们处理feeds时,不需要知道他被存储为哪种格式.
现在让我们加下面的代码到上面的例子中:
- str = feed.build_xml("rss",2.0)
- puts str
我们所做的就是将Atom feed 转换为RSS2.0的feed.你也可以转换成0.9或者1.0版本.因此我们能读一个RSS的feed然后制造出一个Atom的feed.这个就是这个库的强大之处.
这里要强调一下,我们上面的例子都只是一个小测试,如果你要真正做一个应用程序的话,你要注意处理你的缓存.
打开 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