golang网站食谱数据抓取与解析插件库go-recipe的使用

golang网站食谱数据抓取与解析插件库go-recipe的使用

go-recipe-logo

go-recipe 是一个用于从网站抓取食谱数据的 Go 库。

安装

$ go get github.com/kkyr/go-recipe@latest

使用示例

下面是一个完整的示例代码,展示如何使用 go-recipe 抓取和解析食谱数据:

package main

import (
	"fmt"
	"github.com/kkyr/go-recipe/pkg/recipe"
)

func main() {
	// 指定要抓取的食谱URL
	url := "https://minimalistbaker.com/quick-pickled-jalapenos/"

	// 使用ScrapeURL函数抓取食谱数据
	recipe, err := recipe.ScrapeURL(url)
	if err != nil {
		fmt.Printf("抓取食谱失败: %v\n", err)
		return
	}

	// 获取食谱名称
	if name, ok := recipe.Name(); ok {
		fmt.Printf("食谱名称: %s\n", name)
	}

	// 获取食材列表
	if ingredients, ok := recipe.Ingredients(); ok {
		fmt.Println("\n食材:")
		for _, ing := range ingredients {
			fmt.Printf("- %s\n", ing)
		}
	}

	// 获取制作步骤
	if instructions, ok := recipe.Instructions(); ok {
		fmt.Println("\n制作步骤:")
		for i, step := range instructions {
			fmt.Printf("%d. %s\n", i+1, step)
		}
	}

	// 获取烹饪时间
	if cookTime, ok := recipe.CookTime(); ok {
		fmt.Printf("\n烹饪时间: %s\n", cookTime)
	}

	// 获取准备时间
	if prepTime, ok := recipe.PrepTime(); ok {
		fmt.Printf("准备时间: %s\n", prepTime)
	}

	// 获取总时间
	if totalTime, ok := recipe.TotalTime(); ok {
		fmt.Printf("总时间: %s\n", totalTime)
	}

	// 获取份量
	if yield, ok := recipe.Yield(); ok {
		fmt.Printf("份量: %s\n", yield)
	}
}

工作原理

go-recipe 的默认抓取器会查找目标网站上的 ld+json 编码的 Schema Recipe 数据,并能够检索模式中定义的大多数字段。然而,有些网站的 Schema 数据不完整,或者根本没有以这种格式编码食谱。

因此,go-recipe 提供了针对特定网站的自定义抓取器。这些抓取器可以利用默认抓取器,仅对默认抓取器无法找到数据的字段定义自定义抓取逻辑。

贡献

欢迎贡献!您可以通过以下几种方式做出贡献:

  • 添加自定义抓取器
  • 修复bug
  • 基于路线图实现功能
  • 添加您希望看到的其他功能

创建自定义抓取器

使用 go-recipe 包含的代码生成器可以轻松创建自定义抓取器。生成器需要两个参数:食谱网站的链接和托管食谱的网站域名。

运行以下命令(在 go-recipe 包目录中):

$ go run cmd/scrapergen/*.go \
  -d CopyKat \
  -u https://copykat.com/dunkin-donuts-caramel-iced-coffee

(将域名和链接替换为您自己的)

重要提示:域名应以 PascalCase 形式提供,以便生成的结构体大小写正确。否则,您的 PR 将不会被批准。

上面的示例命令将生成以下文件:

go-recipe/internal/html/scrape/custom/copykat.go
go-recipe/internal/html/scrape/custom/copykat_test.go
go-recipe/internal/html/scrape/custom/testdata/copykat.com.html

生成器还不能完成所有工作,因此您还需要进行一些最后的调整:

  1. pkg/recipe/scrapers.go 中的 hostToScraper 映射中注册您的自定义抓取器
  2. (可选)修改自定义抓取器以添加您自己的抓取逻辑
  3. 验证生成的测试是否正确
  4. 验证 make lintmake test 是否通过

路线图

  • [ ] 重构 scrapergen 并添加单元测试
  • [ ] 修改 scrapergen 使其也将新抓取器添加到 hostToScraper 映射中
  • [ ] 添加选项让用户指定 HTTP 客户端超时
  • [ ] 添加选项让用户指定"严格"模式:在此模式下仅使用自定义抓取器(如果已定义),否则失败
  • [ ] 添加更多 Schema Recipe 字段
  • [ ] 添加 CLI 包装器,以 JSON 格式提供输出

致谢

go-recipe 深受 recipe-scrapers 的启发。


更多关于golang网站食谱数据抓取与解析插件库go-recipe的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang网站食谱数据抓取与解析插件库go-recipe的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


使用go-recipe进行食谱数据抓取与解析

go-recipe是一个用于抓取和解析网站食谱数据的Golang库,它能够从各种食谱网站提取结构化数据,如食材、步骤、营养信息等。下面我将介绍如何使用这个库。

安装

go get github.com/kkyr/go-recipe

基本用法

1. 从URL抓取食谱

package main

import (
	"fmt"
	"log"

	"github.com/kkyr/go-recipe/pkg/recipe"
)

func main() {
	// 示例食谱URL
	url := "https://www.allrecipes.com/recipe/158968/spinach-and-feta-turkey-burgers/"

	// 创建抓取器
	scraper, err := recipe.NewScraper(url)
	if err != nil {
		log.Fatalf("创建抓取器失败: %v", err)
	}

	// 抓取食谱数据
	recipe, err := scraper.Scrape()
	if err != nil {
		log.Fatalf("抓取失败: %v", err)
	}

	// 打印食谱信息
	fmt.Printf("食谱标题: %s\n", recipe.Name)
	fmt.Printf("作者: %s\n", recipe.Author)
	fmt.Printf("准备时间: %s\n", recipe.PrepTime)
	fmt.Printf("烹饪时间: %s\n", recipe.CookTime)
	fmt.Printf("总时间: %s\n", recipe.TotalTime)
	fmt.Printf("份量: %s\n", recipe.Yield)
	fmt.Printf("评分: %.1f/5 (%d票)\n", recipe.Rating.Value, recipe.Rating.Count)
	
	fmt.Println("\n食材:")
	for _, ingredient := range recipe.Ingredients {
		fmt.Printf("- %s\n", ingredient)
	}
	
	fmt.Println("\n步骤:")
	for i, instruction := range recipe.Instructions {
		fmt.Printf("%d. %s\n", i+1, instruction)
	}
	
	fmt.Println("\n营养信息:")
	for k, v := range recipe.Nutrition {
		fmt.Printf("%s: %s\n", k, v)
	}
}

2. 支持的网站

go-recipe支持许多流行的食谱网站,包括:

  • AllRecipes
  • BBC Good Food
  • Bon Appétit
  • Epicurious
  • Food Network
  • 以及更多…

你可以通过recipe.SupportedDomains()查看完整列表:

func main() {
	domains := recipe.SupportedDomains()
	fmt.Println("支持的网站:")
	for _, domain := range domains {
		fmt.Println("-", domain)
	}
}

高级功能

1. 自定义HTTP客户端

func main() {
	client := &http.Client{
		Timeout: 30 * time.Second,
	}
	
	scraper, err := recipe.NewScraper(
		"https://www.example.com/recipe",
		recipe.WithHTTPClient(client),
	)
	// ...
}

2. 处理图片

func main() {
	scraper, err := recipe.NewScraper(url)
	// ...
	
	recipe, err := scraper.Scrape()
	// ...
	
	// 获取食谱图片URL
	if recipe.Image != nil {
		fmt.Printf("图片URL: %s\n", recipe.Image.URL)
		fmt.Printf("图片宽度: %d\n", recipe.Image.Width)
		fmt.Printf("图片高度: %d\n", recipe.Image.Height)
	}
}

3. 处理分类和标签

func main() {
	scraper, err := recipe.NewScraper(url)
	// ...
	
	recipe, err := scraper.Scrape()
	// ...
	
	fmt.Println("分类:")
	for _, category := range recipe.Categories {
		fmt.Println("-", category)
	}
	
	fmt.Println("标签:")
	for _, keyword := range recipe.Keywords {
		fmt.Println("-", keyword)
	}
}

注意事项

  1. 在使用前请检查目标网站的robots.txt文件,确保允许爬取
  2. 合理设置请求间隔,避免对网站造成过大负担
  3. 网站结构可能变化,需要定期更新解析逻辑
  4. 考虑使用缓存机制避免重复抓取

错误处理

func main() {
	scraper, err := recipe.NewScraper(url)
	if err != nil {
		switch {
		case errors.Is(err, recipe.ErrDomainNotSupported):
			fmt.Println("不支持的网站域名")
		case errors.Is(err, recipe.ErrInvalidURL):
			fmt.Println("无效的URL")
		default:
			fmt.Printf("未知错误: %v\n", err)
		}
		return
	}
	
	recipe, err := scraper.Scrape()
	if err != nil {
		fmt.Printf("抓取失败: %v\n", err)
		return
	}
	// ...
}

go-recipe是一个强大的工具,可以大大简化从各种食谱网站提取结构化数据的过程。通过合理使用,你可以构建自己的食谱数据库、分析工具或个性化推荐系统。

回到顶部