葫芦流 · REST 参考

API 参考

基础路径 /api/v1。使用 Authorization: Bearer hulu_… 鉴权。错误形态为 {"detail": …}。

本页是给开发者的接口参考。若你从未用过葫芦流,请先在控制台完成《入门》,再读《工作流与节点》。当你自己的系统需要用 Bearer 密钥创建工作流或读取行时,再回来看这里。

在「控制台 → API 密钥」创建密钥。原始 token 以 hulu_ 开头且只显示一次——请像密码一样保管。网站登录 cookie 不能用于 /api/v1。

给已会控制台的开发者 能用 Bearer Key 创建、运行、读行
  1. 鉴权
  2. 工作流
  3. 运行
  4. 数据集

鉴权

每个 /api/v1 调用都需要 Bearer 头。会话 cookie 仅用于控制台。密钥无效或缺失返回 401。建议先在控制台验证同一张图,再自动化。

控制台 → API Key。请求头:Authorization: Bearer hulu_…

Authorization: Bearer hulu_…
curl https://huluflow.com/api/v1/workflows \
  -H "Authorization: Bearer $HULU_KEY"

工作流

抓取 / 存储 / 通知节点组成的 DAG。运行按实际请求网页次数消耗额度。

列出工作流

该账号下全部工作流,新的在前。响应字段是 graph_json(不是 graph)。

GET /api/v1/workflows

创建工作流

graph 默认为空 nodes/edges。status 为 active 或 paused。interval_minutes 默认 1440。运行需要剩余额度(保存图不扣)。

POST /api/v1/workflows
Content-Type: application/json

{
  "name": "Product pipeline",
  "status": "paused",
  "interval_minutes": 1440,
  "graph": { "nodes": [], "edges": [] }
}

获取工作流

不是你的 id 则 404。

GET /api/v1/workflows/{id}

更新工作流

部分更新。省略的字段保持不变。传入 graph 会整图替换。额度在运行时检查,保存时不检查。

PATCH /api/v1/workflows/{id}
Content-Type: application/json

{
  "name": "Renamed",
  "status": "active",
  "interval_minutes": 60,
  "graph": { "nodes": [], "edges": [] }
}

删除工作流

删除工作流。返回 {"ok": true}。已经写入的数据集会保留。

DELETE /api/v1/workflows/{id}

{"ok": true}

运行工作流

立即跑图并等到结束。成功返回 WorkflowRun 加 node_runs。引擎或节点失败返回 502,detail 为字符串或 {error, run, node_runs}。

POST /api/v1/workflows/{id}/run
{
  "id": 1,
  "workflow_id": 12,
  "status": "ok",
  "error": null,
  "started_at": "2026-08-24T12:00:00",
  "finished_at": "2026-08-24T12:00:08",
  "node_runs": [
    {
      "id": 10,
      "node_id": "s1",
      "node_type": "scrape",
      "status": "ok",
      "input_json": {},
      "output_json": { "items": [{ "title": "Mug", "url": "https://shop.example/p/mug" }] },
      "error": null
    }
  ]
}

运行历史

新的在前。limit 1–100,默认 20。详情含每个节点的 input_json、output_json、status、error。

GET /api/v1/workflows/{id}/runs?limit=20
GET /api/v1/workflows/{id}/runs/{run_id}

抓取预览(字段发现)

仅字段发现,不写数据集。需要一个已有的工作流 id(你的任意一条)以便鉴权。mode 为 list 或 detail。

POST /api/v1/workflows/{id}/scrape-preview
Content-Type: application/json

{
  "url": "https://example.com/list",
  "mode": "list",
  "requirement": "title, price, url"
}
{
  "ok": true,
  "url": "https://example.com/list",
  "fields": [{ "name": "title", "label": "title", "type": "text" }],
  "sample": [{ "title": "Mug", "url": "https://shop.example/p/mug" }]
}

最小 graph

把这些对象放进 graph.nodes[].config。edges 使用 from 与 to(节点 id),不是 source/target。若你是完全新手,建议先读《工作流与节点》指南,再回来抄 JSON。

{
  "nodes": [
    {
      "id": "g1",
      "type": "url_gen",
      "config": {
        "mode": "range",
        "template": "https://example.com/list?page={page}",
        "param": "page",
        "start": 1,
        "end": 3,
        "step": 1
      }
    },
    {
      "id": "s1",
      "type": "scrape",
      "config": {
        "url": "https://example.com/list",
        "mode": "list",
        "requirement": "title, price, url",
        "limit": 20,
        "fields": [
          { "name": "title", "label": "title", "type": "text" },
          { "name": "url", "label": "url", "type": "url" }
        ]
      }
    },
    {
      "id": "st1",
      "type": "store",
      "config": { "dataset_name": "products", "key_fields": ["url"] }
    }
  ],
  "edges": [
    { "from": "g1", "to": "s1" },
    { "from": "s1", "to": "st1" }
  ]
}

节点配置

把这些对象放进 graph.nodes[].config。edges 使用 from 与 to(节点 id),不是 source/target。若你是完全新手,建议先读《工作流与节点》指南,再回来抄 JSON。

指南:工作流与节点 →

scrape

抓取需要 config.url,和/或上游传来的 items。mode=list 从列表页抽出多行;detail 每个 URL 一行,并可合并父行。发现后保留 fields。limit 限制本节点本次运行处理的 URL 数(默认 20)。input_field 指定列表→详情时上游的链接列。完整白话说明见《工作流与节点》指南。

{
  "url": "https://example.com/item/1",
  "mode": "list | detail",
  "requirement": "title, price, url",
  "limit": 20,
  "input_field": "url",
  "fields": [{ "name": "title", "label": "title", "type": "text" }]
}

url_gen

无输入。range:模板必须含 {param}(默认 page)。list:urls_text 每行一个 URL。最多 500 条。只能连到抓取。新手请先在控制台预览生成数量。

{
  "mode": "range",
  "template": "https://example.com/list?page={page}",
  "param": "page",
  "start": 1,
  "end": 10,
  "step": 1
}
{
  "mode": "list",
  "urls_text": "https://example.com/a\nhttps://example.com/b"
}

store

读取上游 items。dataset_id 钉住已有表;否则用 dataset_name 按名创建或复用。key_fields 做 upsert 身份(默认 url、link)——请用稳定商品 URL。store_fields 可选,限制写入哪些列。

{
  "dataset_id": 4,
  "dataset_name": "products",
  "key_fields": ["url"],
  "store_fields": ["title", "price", "url"]
}

notify

when=new 按行键发新行;when=field_change 与上次同节点输出比较 watch_fields;其他值对整份 items 做哈希。email 默认账号邮箱。测试告警建议连跑两次以建立基线。

{
  "email": "ops@example.com",
  "when": "new | field_change",
  "watch_fields": ["price"],
  "subject": "[HuluFlow] price change"
}

数据集

你拥有的表,含 row_count、column_count,以及 columns [{key, label, type}]。

GET /api/v1/datasets

创建数据集

请求体 {"name": "…"}。空名称变成 New table。存储节点也可用 dataset_name 建表。

POST /api/v1/datasets
Content-Type: application/json

{ "name": "products" }

获取数据集

GET /api/v1/datasets/{id}

列出行

page ≥ 1,limit 1–200(默认 50)。响应:page、page_size、total、total_pages、columns、rows [{id, key_hash, data, created_at, updated_at}]。data 是入库对象。

GET /api/v1/datasets/{id}/rows?page=1&limit=50

导出表

GET /api/v1/datasets/{id}/export?format=csv|json。流式 CSV(UTF-8 BOM)或返回 JSON {id, name, columns, total, rows}。最多 10 万行(超出 413)。控制台提供同样下载。

GET /api/v1/datasets/{id}/export?format=csv
GET /api/v1/datasets/{id}/export?format=json

curl -L "https://huluflow.com/api/v1/datasets/$DATASET_ID/export?format=csv" \
  -H "Authorization: Bearer $HULU_KEY" \
  -o table.csv

节点预设

预设仅支持 scrape、notify、url_gen。

请求体 {name, type, config}。抓取必须已选字段。url_gen 会校验(模板占位符、最多 500 条)。

GET /api/v1/node-presets
POST /api/v1/node-presets
GET /api/v1/node-presets/{id}
DELETE /api/v1/node-presets/{id}
POST /api/v1/node-presets
Content-Type: application/json

{
  "name": "List scrape",
  "type": "scrape",
  "config": {
    "mode": "list",
    "url": "https://example.com/list",
    "fields": [{ "name": "title", "label": "title", "type": "text" }]
  }
}

错误

错误形态为 {"detail": …}。创建/更新超额为 HTTP 402。运行失败为 502。

401 密钥无效。402 额度不足。404 找不到工作流/运行/数据集/预设。400 请求体或预览 URL 不合法。502 抓取引擎或运行失败。FastAPI 错误形态为 {"detail": … },detail 可以是字符串或对象。

成功形态

{ "ok": true }

错误形态

{ "detail": "Invalid API key" }

配额拒绝

额度不足时 POST …/run(或定时运行)返回 402。升级或等待下个周期后再试。

{ "detail": "Credit quota exceeded" }
HTTP 402

限制

额度 = 本周期内抓取节点实际请求网页次数。URL 生成单节点最多 500 个 URL。抓取默认每次运行每节点最多 20 个 URL。数据集每页最多 200 行;导出最多 100,000 行。运行列表最多 100。预览用于发现字段,不是批量抽取。

数据模型

各端点共享的请求头、响应体与错误格式。

数据模型 →

接下来

需要字段级配置时看节点指南;要可复制 curl 流程看 API 优先。