首页 / 文档 / 自定义 Recipe

自定义 Recipe

Aneiang.Pa 支持四种 Recipe 来源,新增平台无需修改框架代码:

方式适用场景写法
内置 YAML开箱即用20 个平台已嵌入 dll
外部 YAML/JSON配置外置,社区共享Pa.Configure(c => c.UseRecipesFolder(...))
Builder DSL动态构造、运行时定义Pa.Define("Name", b => b.Get(...).ParseHtml(...))
特性标注强类型、IDE 友好[Recipe][Get][Container][Selector] 标注类

YAML Recipe

最推荐的方式。写一份 .yaml 文件即可新增平台:

# recipes/news/cnbeta.yaml
name: CnBeta
category: News
display_name: CnBeta 头条
fetch:
  url: https://www.cnbeta.com.tw/
  headers:
    User-Agent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
parse:
  type: html
  container: ".items-area .item"
  fields:
    title:  { selector: "h2 a", trim: true }
    url:    { selector: "h2 a", attr: href }
    desc:   { selector: ".desc" }

加载并使用:

Pa.Configure(c => c.UseRecipesFolder("./recipes"));
var data = await Pa.Source("CnBeta").GetAsync();

YAML 字段说明

字段说明必填
name数据源唯一标识
category分类(News / Tech / Lottery 等)
display_name显示名称
fetch.url请求地址
fetch.headers自定义请求头
fetch.methodHTTP 方法(默认 GET)
parse.type解析类型(html / json
parse.container容器选择器
parse.fields字段映射

JSON API Recipe

如果目标站点返回 JSON:

name: HackerNews
category: News
display_name: Hacker News
fetch:
  url: https://hn.algolia.com/api/v1/search?tags=front_page
parse:
  type: json
  items: "$.hits"
  fields:
    title: "$.title"
    url:   "$.url"
    points: "$.points"

变量占位

Recipe 中可以使用 {variable} 占位,由中间件动态填充:

name: MyAPI
category: Custom
display_name: 需要 Token 的 API
fetch:
  url: https://api.example.com/items?token={token}
  headers:
    Authorization: "Bearer {token}"

Builder DSL

在 C# 代码中动态构造 Recipe:

Pa.Define("MyAPI", b => b
    .Category("Custom")
    .DisplayName("我的 API")
    .Get("https://api.example.com/items?page={pageNo}")
    .Header("Authorization", "Bearer xxx")
    .ParseJson(p => p
        .Items("$.data")
        .Field("id", "id")
        .Field("title", "title")
        .Field("url", "url")));

var data = await Pa.Source("MyAPI").WithPaging(1, 30).GetAsync();

Builder DSL 解析 HTML

Pa.Define("MyHtml", b => b
    .Category("News")
    .DisplayName("自定义 HTML")
    .Get("https://example.com/news")
    .ParseHtml(p => p
        .Container(".news-item")
        .Field("title", f => f.Selector("h2 a").Trim())
        .Field("url", f => f.Selector("h2 a").Attr("href"))
        .Field("date", f => f.Selector(".date"))));

特性标注

用 C# 特性直接标注 POCO 类,适合强类型场景:

[Recipe("MyTrending", Category = "Tech")]
[Get("https://github.com/trending")]
[Container("article.Box-row")]
public class Repo
{
    [Selector("h2 a")]                                              public string? Title { get; set; }
    [Selector("h2 a", Attr = "href", Base = "https://github.com")]  public string? Url { get; set; }
    [Selector("span[itemprop=programmingLanguage]")]                public string? Lang { get; set; }
}

Pa.DiscoverFromLoadedAssemblies();
var data = await Pa.Source("MyTrending").GetAsync<Repo>();

贡献 Recipe

只需 3 步:

  1. recipes/ 目录新建 .yaml 文件
  2. 填写 name / fetch / parse 三个部分
  3. 提交 PR

新增平台不需要写 C# 代码 —— 提交一份 YAML 文件就能让全世界的 .NET 用户用上你贡献的平台。