gofeed
Gofeed:一个强大的 Golang Feed 解析器
gofeed
是一个功能强大且灵活的库,专为解析各种格式和版本的 RSS、Atom 和 JSON feed 而设计。它能有效处理非标准元素和已知扩展,并对常见的 feed 问题表现出很强的适应性。
目录
特性
全面的 Feed 支持
- RSS(0.90 到 2.0)
- Atom(0.3,1.0)
- JSON(1.0,1.1)
处理无效 Feed
gofeed
采用尽力而为的方法来处理损坏或无效的 XML feed,能够处理以下问题:
- 未转义的标记
- 未声明的命名空间前缀
- 缺失或非法标签
- 不正确的日期格式
- ...等等
扩展支持
gofeed
将 feed 默认命名空间之外的元素视为扩展,将它们存储在 Feed.Extensions 和 Item.Extensions 下的树状结构中。这个特性使您可以轻松访问自定义扩展元素。
内置支持常用扩展 为了更加方便,gofeed 内置了对某些知名扩展的原生解析支持,将其解析为专用结构体。目前支持:
- Dublin Core:通过
Feed.DublinCoreExt
和Item.DublinCoreExt
访问 - Apple iTunes:通过
Feed.ITunesExt
和Item.ITunesExt
访问
概述
在 gofeed
中,您有两种主要的 feed 解析选择:一个通用解析器,可以无缝处理多种 feed 类型;以及专门的解析器,可以更精细地控制单个 feed 类型。
通用 Feed 解析器
通用的 gofeed.Parser
旨在简化处理各种类型 feed(RSS、Atom、JSON)的过程,将它们转换为统一的 gofeed.Feed
模型。当您需要处理多种 feed 格式并希望以相同方式处理它们时,这种方法特别有用。
通用解析器使用内置的转换器,如 DefaultRSSTranslator
、DefaultAtomTranslator
和 DefaultJSONTranslator
,将特定 feed 类型转换为通用 feed。如果您对默认设置不满意,可以实现自己的 gofeed.Translator
来定制转换过程。
专门的 Feed 解析器:RSS、Atom、JSON
另一方面,如果您只关注单一 feed 类型,那么使用专门的解析器在性能和精细度方面会有优势。例如,如果您只对 RSS feed 感兴趣,可以直接使用 rss.Parser
。这些特定于 feed 的解析器将字段映射到其对应的模型,确保名称和结构与 feed 类型完全匹配。
基本用法
通用 Feed 解析器
以下是使用 gofeed.Parser
解析 feed 的方法:
从 URL 解析
fp := gofeed.NewParser()
feed, _ := fp.ParseURL("http://feeds.twit.tv/twit.xml")
fmt.Println(feed.Title)
从字符串解析
feedData := `<rss version="2.0">
<channel>
<title>Sample Feed</title>
</channel>
</rss>`
fp := gofeed.NewParser()
feed, _ := fp.ParseString(feedData)
fmt.Println(feed.Title)
从 io.Reader 解析
file, _ := os.Open("/path/to/a/file.xml")
defer file.Close()
fp := gofeed.NewParser()
feed, _ := fp.Parse(file)
fmt.Println(feed.Title)
从 URL 解析,设置 60 秒超时
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
fp := gofeed.NewParser()
feed, _ := fp.ParseURLWithContext("http://feeds.twit.tv/twit.xml", ctx)
fmt.Println(feed.Title)
从 URL 解析,使用自定义 User-Agent
fp := gofeed.NewParser()
fp.UserAgent = "MyCustomAgent 1.0"
feed, _ := fp.ParseURL("http://feeds.twit.tv/twit.xml")
fmt.Println(feed.Title)
特定订阅源解析器
如果您的使用场景需要专门的解析器:
RSS 订阅源
feedData := `<rss version="2.0">
<channel>
<webMaster>example@site.com (Example Name)</webMaster>
</channel>
</rss>`
fp := rss.Parser{}
rssFeed, _ := fp.Parse(strings.NewReader(feedData))
fmt.Println(rssFeed.WebMaster)
Atom 订阅源
feedData := `<feed xmlns="http://www.w3.org/2005/Atom">
<subtitle>Example Atom</subtitle>
</feed>`
fp := atom.Parser{}
atomFeed, _ := fp.Parse(strings.NewReader(feedData))
fmt.Println(atomFeed.Subtitle)
JSON 订阅源
feedData := `{"version":"1.0", "home_page_url": "https://daringfireball.net"}`
fp := json.Parser{}
jsonFeed, _ := fp.Parse(strings.NewReader(feedData))
fmt.Println(jsonFeed.HomePageURL)
高级用法
使用基本身份验证
fp := gofeed.NewParser()
fp.AuthConfig = &gofeed.Auth{
Username: "foo",
Password: "bar",
}
使用自定义转换器进行高级解析
如果您需要更多地控制字段的解析和优先级,可以指定自己的自定义转换器。以下是一个示例,展示了如何创建自定义转换器,以使RSS订阅源中的 /rss/channel/itunes:author
字段优先于 /rss/channel/managingEditor
字段。
步骤1: 定义您的自定义转换器
首先,我们将创建一个新类型,嵌入库提供的默认RSS转换器。我们将覆盖其Translate方法来实现我们的自定义逻辑。
type MyCustomTranslator struct {
defaultTranslator *gofeed.DefaultRSSTranslator
}
func NewMyCustomTranslator() *MyCustomTranslator {
t := &MyCustomTranslator{}
t.defaultTranslator = &gofeed.DefaultRSSTranslator{}
return t
}
func (ct *MyCustomTranslator) Translate(feed interface{}) (*gofeed.Feed, error) {
rss, found := feed.(*rss.Feed)
if !found {
return nil, fmt.Errorf("Feed did not match expected type of *rss.Feed")
}
f, err := ct.defaultTranslator.Translate(rss)
if err != nil {
return nil, err
}
// 自定义逻辑,优先使用iTunes作者而非管理编辑
if rss.ITunesExt != nil && rss.ITunesExt.Author != "" {
f.Author = rss.ITunesExt.Author
} else {
f.Author = rss.ManagingEditor
}
return f, nil
}
步骤2: 使用您的自定义转换器
一旦定义了自定义转换器,您可以告诉gofeed.Parser使用它而不是默认转换器。
feedData := `<rss version="2.0">
<channel>
<managingEditor>Ender Wiggin</managingEditor>
<itunes:author>Valentine Wiggin</itunes:author>
</channel>
</rss>`
fp := gofeed.NewParser()
fp.RSSTranslator = NewMyCustomTranslator()
feed, _ := fp.ParseString(feedData)
fmt.Println(feed.Author) // Valentine Wiggin
依赖项
许可证
本项目采用MIT许可证
致谢
- cristoper对实现xml:base相对URI处理的贡献。
- Mark Pilgrim和Kurt McKee对优秀的Universal Feed Parser Python库的贡献。该库是
gofeed
库的灵感来源。 - Dan MacTough对node-feedparser的贡献。它为混合
gofeed.Feed
模型中应该涵盖的字段集提供了灵感。 - Matt Jibson在goread项目中的日期解析函数。
- Jim Teeuwen在go-pkg-rss库中表示任意订阅源扩展的方法。
- Sudhanshu Raheja对JSON Feed解析器的支持。