自动化 · 9 分钟阅读

自己做数据看板(下):以 Notion/表格为内容源的自动发布工作流

用状态字段驱动发布流程,Notion Database 或 Google Sheet 作为唯一内容源,通过 GitHub Actions、Cloudflare Pages Deploy Hook 与 Webhook 实现写完即自动上线,并附带失败告警与回滚方法。

上一篇搭好了「数据自动进来」的管道,这篇解决另一半:内容自动出去。目标是让发布动作从「登录后台、复制粘贴、点部署」变成在 Notion 里把一个状态从「草稿」改成「已发布」——剩下的全部自动完成。

核心思想:状态字段驱动一切

不要用「有没有这个文件」来表达发布意图,那会把草稿、定时稿、下线稿混为一谈。正确做法是在内容源里设置明确的状态机:

状态含义系统行为
Draft 草稿写作中不同步,不进任何构建
Scheduled 定时已写完,等待发布时间到点后自动转为发布
Published 已发布正式内容同步入库 → 触发构建 → 上线
Archived 归档下线但保留从站点移除,数据留存

再配两个字段:pubDate(决定定时发布时刻)、slug(决定 URL,一经发布永不再改,否则旧链接全断)。

三种内容源,按团队阶段选

内容源适合阶段自动发布方式
GitHub 仓库里的 Markdown单人、技术型push 即发布(最简单,本站当前模式)
Notion Database想在编辑器里写作、手机也能改Actions 定时/ Webhook 拉取转换
Google Sheet / Airtable结构化榜单、比价表类内容CSV/API 拉取后生成页面

本站一期采用第一种(Markdown + Cloudflare Pages 自动部署),二期升级到第二种。下面把两种触发机制都讲清楚。

触发方式一:Deploy Hook(最简单,先跑通它)

Cloudflare Pages 提供一个「构建钩子」URL:收到任意一次对这个 URL 的 POST 请求,就会重新拉取代码并构建发布。在 Pages 项目 → Settings → Builds & deployments → Deploy Hooks 里创建,得到形如:

https://api.cloudflare.com/client/v4/pages/webhooks/deploy_pages/xxxxxxxx

把它当密钥对待——任何拿到这个 URL 的人都能触发你的构建,只存在 GitHub Secrets 里,命名为 CF_DEPLOY_HOOK。

最小的手动触发工作流 .github/workflows/publish.yml:

name: trigger-publish

on:
  workflow_dispatch:        # Actions 页面点按钮运行,先验证链路
  repository_dispatch:      # 供外部 Webhook 调用(见下文)

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: 触发 Cloudflare Pages 构建
        run: |
          curl -fsS -X POST "${{ secrets.CF_DEPLOY_HOOK }}"

在 Actions 页面手动点一次,回到 Cloudflare 看到构建开始,说明「按钮 → 上线」链路已通。

触发方式二:Notion 状态变更自动触发

Notion 原生不支持出站 Webhook,但有两个成熟绕法:

  1. 定时轮询(推荐先做):Actions 每 15 分钟查一次 Notion Database,发现 status = Published 但站点里还没有的文章,就拉取、转换、提交,然后触发 Deploy Hook。延迟最多 15 分钟,对内容站完全够用,且最稳定;
  2. Notion 自动化平台转发:用 Make/Zapier 监听数据库更新,再向 GitHub 发送 repository_dispatch 事件,近乎实时,但要依赖第三方平台的免费额度。

轮询工作流骨架:

name: notion-sync

on:
  schedule:
    - cron: '*/15 * * * *'
  workflow_dispatch:

jobs:
  sync:
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: '3.12'
      - run: pip install -r requirements.txt
      - name: 拉取 Notion 已发布文章
        env:
          NOTION_TOKEN: ${{ secrets.NOTION_TOKEN }}
          NOTION_DATABASE_ID: ${{ secrets.NOTION_DATABASE_ID }}
        run: python scripts/notion_sync.py
      - name: 有变更才触发部署
        run: |
          if [[ -n $(git status --porcelain) ]]; then
            git config user.name "opc-bot"
            git config user.email "[email protected]"
            git add src/content/articles
            git commit -m "chore: sync published posts from notion"
            git push
            curl -fsS -X POST "${{ secrets.CF_DEPLOY_HOOK }}"
          else
            echo "没有新内容,跳过部署"
          fi

notion_sync.py 的职责单一:查询 Published 页面 → 调 Blocks API 取正文 → 转成本站约定的 Markdown + frontmatter(字段对齐 src/content.config.ts 的 schema)→ 图片下载本地化 → 写入 src/content/articles/<模块>/<slug>.md。状态变为 Archived 的页面则删除对应文件。

这正是本站二期的落地方案:模板层完全不用改,只多一个「Notion → Markdown」的转换脚本。

定时发布:让 Scheduled 到点自动上线

两个实现层次:

  • 简单版:Notion 里写好 pubDate,状态直接给 Published,轮询脚本只同步 pubDate <= 当前时间 的文章——提前一周写好的内容到点自然出现;
  • 精细版:状态保持 Scheduled,脚本每次运行时把「已到点」的条目先通过 Notion API 改成 Published 再同步,后台状态与线上完全一致。

多渠道分发:一次发布,多处更新

内容站上 Cloudflare 之后,同一套状态机还能驱动其他渠道,思路都是订阅「发布成功」这个事件:

  • RSS / sitemap:本站已在构建时自动生成,第三方聚合器自动来抓;
  • 社媒/社群通知:构建成功后增加一步,调用 Telegram Bot / 邮件 API 推送新文章链接;
  • 搜索引擎收录:调用 IndexNow 或 Google Indexing API 主动推送新 URL,缩短收录等待;
  • 跨站同步:再发一个 Webhook 给 Make,由它改写发布到其他平台。

原则:每个渠道都做成流水线里一个「失败不阻塞主流程」的步骤,通知挂了不应该导致文章发不出去。

告警、回滚与安全

  • 失败要响:工作流任意一步失败(Notion 限流、转换报错、部署钩子非 2xx),让 GitHub 发失败邮件;关键流程可加一步发 Telegram 告警;
  • 内容回滚靠 Git:每次同步都是一次 commit,线上出问题在 Cloudflare 选历史部署一键回退,或 git revert 对应提交后重新部署;
  • 幂等设计:脚本可安全重跑——已存在且无变化的文章跳过,靠 slug 去重,避免重复生成;
  • 密钥三处隔离:NOTION_TOKEN、NOTION_DATABASE_ID、CF_DEPLOY_HOOK 全部只放 GitHub Secrets / Cloudflare 环境变量,不进仓库、不写进日志;
  • 频率与礼貌:轮询间隔不低于 10–15 分钟,并处理 429 限流的退避重试。

实施顺序建议

  1. 先在 Cloudflare 建 Deploy Hook,用 workflow_dispatch 手动触发跑通一次;
  2. 把现有写作流程迁到 Notion Database,字段对齐本站 schema;
  3. 写轮询脚本,先用 workflow_dispatch 手动同步验证 Markdown 产物;
  4. 打开 15 分钟定时任务,验证 Draft/Published 状态门控;
  5. 最后加定时发布、失败告警和多渠道通知。

至此,「自动采集 → 数据看板 → 内容自动发布」就拼成了一个一人公司的最小自动化闭环,全部跑在免费额度上。