XML feed是网站用来分发内容的标准格式,常见的RSS和Atom都属于这类格式,在Ruby中解析这类数据有多种成熟方案。下面先通过一张示意图了解XML feed的基本结构。

一、使用Ruby标准库RSS解析
Ruby标准库自带了RSS模块,不需要额外安装依赖,就可以直接解析常见的RSS和Atom格式feed,适合轻量级使用场景。
1.1 解析RSS格式feed
RSS格式的feed通常以rss为根节点,包含channel和多个item子节点,每个item对应一条内容条目。
require 'rss'
# 示例RSS feed内容,实际使用中可替换为网络请求获取的内容
rss_content = <?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
<channel>
<title>示例RSS源</title>
<link>https://ipipp.com/rss</link>
<item>
<title>第一条新闻</title>
<link>https://ipipp.com/news/1</link>
<pubDate>Mon, 01 Jan 2024 08:00:00 GMT</pubDate>
<description>这是第一条新闻的内容描述</description>
</item>
<item>
<title>第二条新闻</title>
<link>https://ipipp.com/news/2</link>
<pubDate>Tue, 02 Jan 2024 09:00:00 GMT</pubDate>
<description>这是第二条新闻的内容描述</description>
</item>
</channel>
</rss>
begin
# 解析RSS内容
feed = RSS::Parser.parse(rss_content)
# 输出feed基本信息
puts "Feed标题:#{feed.channel.title}"
puts "Feed链接:#{feed.channel.link}"
puts "条目数量:#{feed.items.size}"
# 遍历所有条目提取信息
feed.items.each do |item|
puts "条目标题:#{item.title}"
puts "条目链接:#{item.link}"
puts "发布时间:#{item.pubDate}"
puts "内容描述:#{item.description}"
puts "-------------------"
end
rescue RSS::Error => e
puts "解析失败:#{e.message}"
end1.2 解析Atom格式feed
Atom格式的feed根节点是feed,条目用entry标签表示,结构和RSS略有不同,标准库RSS模块同样支持解析。
require 'rss'
# 示例Atom feed内容
atom_content = <?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>示例Atom源</title>
<link href="https://ipipp.com/atom"/>
<entry>
<title>Atom第一条内容</title>
<link href="https://ipipp.com/atom/1"/>
<updated>2024-01-01T08:00:00Z</updated>
<summary>这是Atom第一条内容的摘要</summary>
</entry>
<entry>
<title>Atom第二条内容</title>
<link href="https://ipipp.com/atom/2"/>
<updated>2024-01-02T09:00:00Z</updated>
<summary>这是Atom第二条内容的摘要</summary>
</entry>
</feed>
begin
feed = RSS::Parser.parse(atom_content)
puts "Feed标题:#{feed.title.content}"
puts "Feed链接:#{feed.link.href}"
puts "条目数量:#{feed.entries.size}"
feed.entries.each do |entry|
puts "条目标题:#{entry.title.content}"
puts "条目链接:#{entry.link.href}"
puts "更新时间:#{entry.updated.content}"
puts "内容摘要:#{entry.summary.content}"
puts "-------------------"
end
rescue RSS::Error => e
puts "解析失败:#{e.message}"
end二、使用Nokogiri库解析复杂场景
如果遇到格式不规范、标准库无法解析的特殊XML feed,或者需要更灵活的节点提取能力,可以使用第三方库Nokogiri,先通过gem install nokogiri安装依赖。
2.1 基础解析示例
Nokogiri可以像操作DOM一样遍历XML节点,适合处理结构特殊的feed。
require 'nokogiri'
# 复用之前的RSS内容
rss_content = <?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
<channel>
<title>示例RSS源</title>
<link>https://ipipp.com/rss</link>
<item>
<title>第一条新闻</title>
<link>https://ipipp.com/news/1</link>
<pubDate>Mon, 01 Jan 2024 08:00:00 GMT</pubDate>
<description>这是第一条新闻的内容描述</description>
</item>
</channel>
</rss>
doc = Nokogiri::XML(rss_content)
# 提取channel标题
channel_title = doc.at_xpath('//channel/title').text
puts "Channel标题:#{channel_title}"
# 提取所有item节点
items = doc.xpath('//item')
items.each do |item|
title = item.at_xpath('title').text
link = item.at_xpath('link').text
pub_date = item.at_xpath('pubDate').text
puts "条目标题:#{title}"
puts "条目链接:#{link}"
puts "发布时间:#{pub_date}"
puts "-------------------"
end2.2 处理命名空间
部分Atom feed会带命名空间,Nokogiri可以通过指定命名空间来正确提取节点内容。
require 'nokogiri'
atom_content = <?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/">
<title>带命名空间的Atom源</title>
<entry>
<title>带媒体内容的条目</title>
<link href="https://ipipp.com/atom/media"/>
<media:thumbnail url="https://ipipp.com/thumb.jpg"/>
</entry>
</feed>
doc = Nokogiri::XML(atom_content)
# 注册命名空间
doc.collect_namespaces.each { |k, v| doc.namespaces[k] = v }
# 提取带命名空间的缩略图地址
thumbnail_url = doc.at_xpath('//xmlns:entry/media:thumbnail/@url').text
puts "缩略图地址:#{thumbnail_url}"三、解析注意事项
- 编码问题:如果feed内容编码不是UTF-8,解析前需要先转换编码,避免乱码,比如使用
content.force_encoding('GBK').encode('UTF-8')处理GBK编码的内容。 - 网络请求:实际使用中通常需要通过Net::HTTP或者Faraday等库请求远程feed地址获取内容,再传入解析方法,注意处理请求超时、404等异常情况。
- 格式兼容:部分老旧feed可能不符合标准规范,标准库解析失败时可以尝试用Nokogiri做容错处理,比如忽略不认识的节点。
以上就是Ruby解析XML feed的常用方法,开发者可以根据项目需求选择合适的方案,标准库适合简单场景,Nokogiri适合复杂定制需求。