golang解析RSS和Atom订阅源的插件库gofeed的使用

Golang解析RSS和Atom订阅源的插件库gofeed的使用

Gofeed: 一个强大的Golang Feed解析器

gofeed是一个强大灵活的库,用于解析各种格式和版本的RSSAtomJSON订阅源。它能有效处理非标准元素和已知扩展,并对常见的订阅源问题表现出良好的容错性。

特性

全面的订阅源支持

  • RSS (0.90 到 2.0)
  • Atom (0.3, 1.0)
  • JSON (1.0, 1.1)

处理无效订阅源

gofeed采用尽力而为的方法处理损坏或无效的XML订阅源,能够处理以下问题:

  • 未转义的标记
  • 未声明的命名空间前缀
  • 缺失或非法的标签
  • 错误的日期格式
  • 以及其他问题

扩展支持

gofeed将默认命名空间之外的元素视为扩展,将它们存储在Feed.Extensions和Item.Extensions下的树状结构中。这个特性让你可以轻松访问自定义扩展元素。

内置支持流行扩展:

  • Dublin Core: 通过Feed.DublinCoreExtItem.DublinCoreExt访问
  • Apple iTunes: 通过Feed.ITunesExtItem.ITunesExt访问

基本用法

通用订阅源解析器

从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)

带60秒超时的URL解析

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)

带自定义User-Agent的URL解析

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",
}

使用自定义翻译器进行高级解析

步骤1: 定义自定义翻译器

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 Author而非Managing Editor
  if rss.ITunesExt != nil && rss.ITunesExt.Author != "" {
    f.Author = rss.ITunesExt.Author
  } else {
    f.Author = rss.ManagingEditor
  }
  
  return f, nil
}

步骤2: 使用自定义翻译器

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

依赖

  • goxpp - XML Pull Parser
  • goquery - Go jQuery-like接口
  • testify - 单元测试增强
  • jsoniter - 更快的JSON解析

许可证

本项目采用MIT许可证

致谢

  • cristoper - 实现xml:base相对URI处理
  • Mark Pilgrim和Kurt McKee - Universal Feed Parser Python库的灵感来源
  • Dan MacTough - node-feedparser提供了混合gofeed.Feed模型应涵盖的字段集灵感
  • Matt Jibson - goread项目中的日期解析函数
  • Jim Teeuwen - go-pkg-rss库中表示任意订阅源扩展的方法
  • Sudhanshu Raheja - 支持JSON Feed解析器

更多关于golang解析RSS和Atom订阅源的插件库gofeed的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang解析RSS和Atom订阅源的插件库gofeed的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


使用gofeed解析RSS和Atom订阅源

gofeed是一个流行的Go语言库,用于解析RSS和Atom格式的订阅源。它提供了简单易用的API,可以处理各种格式的feed,包括RSS 0.9x, RSS 2.0和Atom 1.0。

安装gofeed

首先需要安装gofeed库:

go get github.com/mmcdole/gofeed

基本用法

1. 解析远程feed

package main

import (
	"fmt"
	"github.com/mmcdole/gofeed"
)

func main() {
	fp := gofeed.NewParser()
	feed, err := fp.ParseURL("https://blog.golang.org/feed.atom")
	if err != nil {
		fmt.Printf("Error fetching feed: %v", err)
		return
	}

	fmt.Println("Feed Title:", feed.Title)
	fmt.Println("Feed Link:", feed.Link)
	fmt.Println("Feed Description:", feed.Description)
	fmt.Println("Last Updated:", feed.Updated)

	for _, item := range feed.Items {
		fmt.Println("\n---")
		fmt.Println("Title:", item.Title)
		fmt.Println("Link:", item.Link)
		fmt.Println("Published:", item.Published)
		fmt.Println("Description:", item.Description)
	}
}

2. 解析本地feed文件

package main

import (
	"fmt"
	"github.com/mmcdole/gofeed"
	"os"
)

func main() {
	file, err := os.Open("feed.xml")
	if err != nil {
		fmt.Printf("Error opening file: %v", err)
		return
	}
	defer file.Close()

	fp := gofeed.NewParser()
	feed, err := fp.Parse(file)
	if err != nil {
		fmt.Printf("Error parsing feed: %v", err)
		return
	}

	fmt.Println("Feed Title:", feed.Title)
}

高级功能

1. 自定义解析器

fp := gofeed.NewParser()
fp.RSSTranslator = NewCustomTranslator() // 自定义RSS解析器
fp.AtomTranslator = NewCustomAtomTranslator() // 自定义Atom解析器

2. 处理不同类型的feed

fp := gofeed.NewParser()
feed, err := fp.ParseURL("https://example.com/feed")
if err != nil {
    fmt.Printf("Error fetching feed: %v", err)
    return
}

// 检查feed类型
if feed.FeedType == "rss" {
    fmt.Println("This is an RSS feed")
} else if feed.FeedType == "atom" {
    fmt.Println("This is an Atom feed")
}

3. 处理feed中的图片

for _, item := range feed.Items {
    if item.Image != nil {
        fmt.Println("Image URL:", item.Image.URL)
    }
    
    // 或者从扩展中获取图片
    if ext, ok := item.Extensions["media"]; ok {
        if contents, ok := ext["content"]; ok {
            for _, content := range contents {
                if content.Attrs["medium"] == "image" {
                    fmt.Println("Media Image:", content.Attrs["url"])
                }
            }
        }
    }
}

4. 处理作者信息

for _, item := range feed.Items {
    if item.Author != nil {
        fmt.Println("Author:", item.Author.Name)
        fmt.Println("Author Email:", item.Author.Email)
    }
}

错误处理

gofeed提供了详细的错误信息,可以帮助诊断解析问题:

feed, err := fp.ParseURL("https://example.com/feed")
if err != nil {
    switch err.(type) {
    case *gofeed.HTTPError:
        fmt.Println("HTTP Error:", err)
    case *gofeed.FeedTypeNotRecognizedError:
        fmt.Println("Feed type not recognized:", err)
    case *gofeed.FeedParseError:
        fmt.Println("Feed parse error:", err)
    default:
        fmt.Println("Unknown error:", err)
    }
    return
}

性能考虑

对于需要频繁解析大量feed的应用,可以考虑重用解析器实例:

fp := gofeed.NewParser()

// 在循环中重用解析器
for _, feedURL := range feedURLs {
    feed, err := fp.ParseURL(feedURL)
    if err != nil {
        continue
    }
    // 处理feed
}

gofeed是一个功能强大且灵活的库,可以满足大多数RSS和Atom解析需求。它支持各种feed格式,处理扩展元素,并提供了良好的错误处理机制。

回到顶部