Playwright 自动化浏览器抽奖示例
展示 Playwright + Python + GitHub Actions 工作流的实战案例,技术参考有限但演示完整。
展示 Playwright + Python + GitHub Actions 工作流的实战案例,技术参考有限但演示完整。
AI 驱动的浏览器自动化工作流
旧金山的夏天到了,这意味着每周我都会忘记报名参加免费的 Stern Grove Music Festival 门票抽签。
解决办法是什么?我没有简单地设置一个日历提醒,而是做了任何一位理智的开发者都会做的事:编写一个通过 GitHub Actions 每周运行的 Python 脚本,用 Playwright 抓取音乐节网站,并自动替我报名抽签。
真正有趣的是它的构建过程。我向一个 coding agent 描述了自己的需求(我以前做过很多浏览器自动化项目,比如自动预订网球场、制作数据可视化等),Entire 则记录了整个过程中的每一条 prompt、每一次 tool call 和每一项输出。因此,我拥有一份完整且可审计的记录,可以查看整个项目是如何一步步构建出来的。如果你想亲自回顾完整的构建过程,可以查看对应的实时 session。下面由我带你过一遍:
整个(Entire,哈哈)项目始于我发给 coding agent 的一条消息(我用的是 Claude Code,不过任何 Agent 都可以!)。我先把游戏规则告诉了它:
Stern Grove 的抽签会在每场演出开始前六周的上午 10:00 开放,并持续整整一周供大家报名……
我还把报名按钮的确切 HTML 交给了它。Stern Grove 使用 Tixologi 处理票务,因此 Agent 需要知道自己面对的是什么。
接着,我告诉它 GitHub Action 可以访问哪些 secrets:
Resend API key(用于发送通知)
“发件人”邮箱地址
邮政编码
这些信息全都以加密 secrets 的形式保存在 GitHub Actions 中,绝不会提交到 repo。我从一开始就确保 Agent 理解这一约束。
在编写任何实现代码之前,Agent 先研究了需求规格,提出了一个澄清问题,然后给出了一套简洁的设计:
lottery.py——入口点,由 GitHub Actions 的 cron schedule 触发
browser.py——包含全部 Playwright 逻辑:网页抓取和浏览器自动化
state.py——加载并保存 entered_lotteries.json,确保不会重复报名
notify.py——通过 Resend 发送成功和失败邮件
状态持久化是其中最巧妙的部分。对于一个每周只运行一次的任务,无须专门搭建数据库;已经报名的抽签会记录在一个 JSON 文件中,并在每次运行后提交回 repo:
{
"entered": [
{ "event_id": "abc123", "show": "Show Name", "entered_at": "2025-06-21T10:02:00Z" }
]
}
cron schedule 位于 workflow 文件中:
# .github/workflows/lottery.yml
on:
schedule:
- cron: "0 17 * * 1" # weekly check
workflow_dispatch:
这里有一个步骤特别值得强调。在接触任何浏览器逻辑之前,Agent 先实时检查了 Stern Grove 的实际页面,尤其是 window.tixologiWidget.concerts,以了解真实的数据结构,而不是凭空猜测。
Tixologi 是一个票务和活动管理平台。通过这次检查,Agent 记录了准确的字段名称、ISO 8601 日期格式以及 event ID 的结构。它捕获的一条 console log 为后续省去了大量调试工作:
// What the page actually exposes
window.tixologyWidget.concerts
// → [{ eventId, name, startDate: "2025-07-13T19:00:00Z", ... }]
让实现建立在真实观察到的数据之上,而不是主观假设之上,是区分两类代码的关键:一类能在首次真实运行时正常工作,另一类则会在生产环境中悄无声息地失败。
state.py 不只是读取 JSON。报名成功后,它还会使用 GitHub Personal Access Token(PAT)提交并推送更新,让下一次运行知道哪些抽签已经报过名:
def commit_state(token: str) -> None:
subprocess.run(["git", "add", "entered_lotteries.json"], check=True)
subprocess.run(["git", "commit", "-m", "Update entered lotteries"], check=True)
subprocess.run(["git", "push"], check=True)
Agent 添加 notify.py 后,一个负责审查的 sub-agent 立刻在 diff 中指出了两个问题:
它使用了 print() 语句,而不是 logging 模块。
它重复初始化了用于邮件发送的 Resend API key。
Agent 在继续下一个任务之前修复了这两个问题。这正是“任务 → 审查”循环应有的作用:捕获那些通常要过几周才会暴露出来的马虎问题。
import logging
logger = logging.getLogger(__name__)
resend.api_key = os.environ["RESEND_API_KEY"] # initialized once
def notify_success(show: str) -> None:
logger.info("Entered lottery for %s", show)
resend.Emails.send({ ... })
这部分确实让我觉得非常实用:我不必记住这套自动化是如何构建出来的,因为 Entire 已经捕获了全部过程。Entire 中的一个 session,就是一次 AI coding 交互的完整记录,也就是每一条 prompt、每一条响应、每一次 tool call 和每一处文件变更。你可以在前面提到的 session 页面中浏览我的记录。
下面是浏览方法:
找到 session。 Session 位于 checkpoint 详情页的 Sessions 标签页中。每一行都会显示运行的 Agent(我这里是 Claude Code)、步骤数量、开场 prompt 和时间戳。点击其中一项即可打开对应的时间线。
阅读时间线。 Session 时间线会按顺序展示整个对话,包括我的 prompt、Agent 的响应、可展开的 tool call 和 runtime 标签。metadata 面板会汇总本次运行使用的 model、持续时间和 token 用量。
展开任意 tool call。 Tool call 会显示为可展开的行,展开后可以看到确切的参数和结果。如果是文件编辑操作,还会直接显示对应的 diff。
过滤噪声。 右侧的 filters 栏可以切换要显示的内容,包括 prompt、响应、中间步骤、checkpoint 和 tool call。tool call 还能进一步细分为文件编辑、bash、读取和其他操作。当我只想查看更高层次的信息时,就会取消勾选一些内容,让视图更清爽。
深入查看 sub-agent。 当 Agent 通过 Claude Code 的 Task tool 启动负责审查的 sub-agent 时,Entire 会将它捕获为一个独立 session。这个 session 拥有自己的 transcript 和 tool call,同时其数据也会汇总到父 checkpoint 的统计中。你可以在那里准确看到审查循环是如何发现 print()/logging 问题的。
跳转到代码。 每个 session 都会通过 Entire-Checkpoint trailer 链接回对应的 Git commit,因此你可以打开匹配的 checkpoint,或者直接查看 GitHub 上的底层 commit。metadata 本身保存在一条独立的 entire/checkpoints/v1 branch 上,从而保持主分支历史整洁。所以,你看到的录屏并不是唯一记录——每一行代码背后的完整推理过程都保存在那个 session 中,随时可以回退查看。
说实话,第一次真实运行失败了。CI 很少会在第一次尝试时就乖乖配合,这次也不例外。我遇到了两个环境问题:
Ubuntu 版本漂移。 为了兼容 Playwright,我不得不将 runner 固定到 Ubuntu 22.04。ubuntu-latest 在 2025 年悄悄变成了 Ubuntu 24.04,而 libasound2 package 也在这个过程中被重命名了。
Chromium 依赖。 最后,我没有依赖 Playwright 自带的 installer,而是使用正确的 Ubuntu 24.04 package 名称,手动安装 Chromium 的依赖。
修复前是这样:
# before
- run: playwright install --with-deps chromium
后来改成了显式安装 apt 依赖,再配合一个更精简的 Playwright 步骤:
# after
- run: |
sudo apt-get update
sudo apt-get install -y libasound2t64 libnss3 libnspr4 # ...correct 24.04 names
- run: playwright install chromium
最终,它顺利运行了。我收到了 Stern Grove 和 Resend 发来的确认邮件。
整套技术栈配合得非常漂亮:
Playwright 负责浏览器自动化
GitHub Actions 负责每周 cron schedule 和 secrets 管理
Resend 负责发送成功或失败通知
coding agent(Claude Code)负责构建项目,并通过审查循环发现真实 bug
Entire 捕获每一条 prompt、每一次 tool call 和每一项输出,并将它们关联到相应的 commit
我已经迫不及待想看看你会用这些组件构建出什么了。现在,这个夏天你和我都不会再忘记报名 Stern Grove 抽签。
如需采取进一步措施,你可以考虑屏蔽此人和/或举报滥用行为。