🎁 Get the FREE AI Skills Starter GuideSubscribe →
BytesAgainBytesAgain
🦀 ClawHub

Shanghai Library Seat Booking

by @jenslewie

上海图书馆东馆三楼座位预约。支持浏览器自动化登录获取认证信息,以及基于API的座位预约(指定座位或系统自动分配)。适用于需要自动化预约图书馆座位的场景。

Versionv0.1.9
Downloads796
Stars1
TERMINAL
clawhub install shlibrary-seat-booking

📖 About This Skill


name: shlibrary-seat-booking description: 上海图书馆东馆三楼座位预约。支持浏览器自动化登录获取认证信息,以及基于API的座位预约(指定座位或系统自动分配)。适用于需要自动化预约图书馆座位的场景。 homepage: https://github.com/jenslewie/jenslewie-skills/tree/main/shlibrary-seat-booking metadata: openclaw: emoji: "📚" homepage: https://github.com/jenslewie/jenslewie-skills/tree/main/shlibrary-seat-booking requires: bins: - node - npm - npx install: - kind: brew formula: node bins: [node, npm, npx] label: Install Node.js - kind: node package: playwright bins: [playwright] label: Install Playwright

上海图书馆座位预约

通过上海图书馆预约接口,预约东馆三楼阅览座位。

功能特性

  • 浏览器辅助登录 - 手动完成登录后,自动获取认证信息
  • 读取本地认证信息 - 从 profile 文件读取认证信息
  • 登录态自动刷新 - profile 文件来源的认证缺失或失效时,会自动拉起登录流程
  • 支持时段标签 - "上午 / 下午 / 晚上"映射到具体时间
  • 支持中文参数值 - 支持 --area 南区 --seat-row 4排 --seat-no 2号 这样的直观输入
  • 整天预约模式 - 一键预约当天所有时段
  • 检查指定座位可用性 - 指定座位预约前自动检查目标座位
  • 提交指定座位预约 - 预约特定座位
  • 系统自动分配预约 - 让系统分配可用座位
  • 查询整天公共可用座位 - 查询某一天全部时段都可用的座位列表
  • 查询当前账号已有预约 - 查看预约记录
  • 取消指定预约 - 取消已有预约
  • 多账号支持 - 通过 --profile 切换不同账号
  • 前置条件

    1. 拥有上海图书馆读者证(已开通借阅功能) 2. 已安装依赖(如果使用浏览器登录功能) 3. 如果使用预约模式,需要知道 日期和时段 4. 如果使用指定座位模式,还需要知道 区域、排号和座位号 5. 如果要切换到另一个账号,可以额外准备一个 profile 对应的认证文件 6. 不要求事先手动登录或手动保存认证文件;当使用 profile 文件时,book_seat.js 会在认证缺失或失效时自动拉起登录流程

    适用方式

    当前推荐统一使用子命令入口:

  • availability:查询某天全部时段都可用的座位
  • list:查询当前账号已有预约
  • cancel:取消指定预约
  • book:预约座位
  • 当前脚本支持两类预约:

  • 指定座位模式:先查这个座位是否可用,再决定是否提交预约
  • 自动分配模式:不指定区域/排号/座位号,直接请求系统分配一个可用座位
  • 参数约定:

  • availability --date [日期] [--area 区域...]
  • - --date:必填,表示查询哪一天 - --area:可选,表示只扫描哪些区域;不传就查询全部区域
  • list [--profile 名称]
  • - 不接受其他业务参数
  • cancel --reservation-id [预约ID]
  • - --reservation-id:必填,只负责指定要取消哪条预约
  • book --date [日期] [--period 时段] [--area 区域] [--seat-row 排号] [--seat-no 座位号]
  • - 只有 --date:整天自动分配 - --date + --period:单时段自动分配 - --date + --area + --seat-row + --seat-no:整天指定座位 - --date + --period + --area + --seat-row + --seat-no:单时段指定座位 - 参数值支持中文格式,例如:--area 南区 --seat-row 4排 --seat-no 2号

    常用命令速查

    # 查询当前账号预约
    node ./scripts/book_seat.js list

    查询指定账号预约

    node ./scripts/book_seat.js list --profile user1

    查询 3 月 20 日在多个区域里整天都可用的座位

    node ./scripts/book_seat.js availability --profile user1 --date 2026-03-20 --area 北区 西区 东区

    查询 3 月 20 日全部区域里整天都可用的座位

    node ./scripts/book_seat.js availability --profile user1 --date 2026-03-20

    取消预约

    node ./scripts/book_seat.js cancel --profile user1 --reservation-id 5187335

    按时段自动分配

    node ./scripts/book_seat.js book --profile user1 --date 2026-03-24 --period 上午

    按时段指定座位

    node ./scripts/book_seat.js book --profile user1 --date 2026-03-24 --period 下午 --area 南区 --seat-row 4 --seat-no 5

    整天自动分配

    node ./scripts/book_seat.js book --profile user1 --date 2026-03-24

    整天指定座位

    node ./scripts/book_seat.js book --profile user1 --date 2026-03-24 --area 南区 --seat-row 4 --seat-no 5

    说明:

  • 不传 --profile 就使用默认账号
  • --profile 会读取默认 profile 根目录下的 profiles/.json
  • 默认 profile 根目录是 ~/.config/shlibrary-seat-booking
  • 也可以通过 --profile-dir--auth-file 显式指定认证文件位置
  • 如果 profile 文件缺失或认证失效,脚本会自动拉起登录
  • 快速开始

    方式1: 浏览器自动化登录(推荐)

    Skill 提供了基于 Node.js + Playwright 的浏览器自动化脚本,可以自动完成登录并获取认证信息:

    #### 安装依赖

    # 在 skill 目录内安装 Playwright
    cd /path/to/shlibrary-seat-booking
    npm install playwright

    安装浏览器二进制

    npx playwright install chromium

    说明:

  • 请在 skill 目录内执行 npm install playwright,这样 node ./scripts/*.js 才能稳定加载本地 playwright 依赖
  • npx playwright install chromium 会联网下载 Chromium 浏览器二进制
  • #### 运行登录脚本

    # 默认账号登录
    node ./scripts/login.js

    指定profile登录

    node ./scripts/login.js --profile user1

    指定 profile 根目录

    node ./scripts/login.js --profile user1 --profile-dir ~/.config/shlibrary-seat-booking

    直接指定认证文件

    node ./scripts/login.js --auth-file ~/.config/shlibrary-seat-booking/profiles/user1.json

    脚本会: 1. 打开浏览器并访问登录页面 2. 由你手动完成用户名、密码、验证码登录 3. 登录成功后自动检测并继续 4. 自动进入 seatyy / service/yuyue,优先直接调用 queryAuthInfo 5. 只有门户没有自动准备好时,才兜底尝试点击“预约”入口 6. 保存到对应的认证文件(默认 ~/.config/shlibrary-seat-booking/profiles/default.json

    #### 技术实现

  • 纯 Node.js 实现 - 使用 Playwright 打开浏览器
  • 手动登录 + 自动提取 - 登录动作由你完成,认证提取由脚本完成
  • 优先直连门户接口 - 先走 seatyy -> service/yuyue -> queryAuthInfo
  • 调用 queryAuthInfo - 自动获取 accessTokensigntimestamp
  • 多账号支持 - 通过 --profile 参数管理多个账号
  • 方式2: 手动获取认证信息

    如果你更喜欢手动操作,或者想排查认证问题:

    1. 先通过门户进入预约系统(通常会经过 service/seatyyservice/yuyue) 2. 使用读者证登录 3. 按 F12 打开浏览器开发者工具 4. 切换到 Network(网络)标签 5. 进入任意可触发预约系统接口的页面 6. 查看任意预约 API 请求的 Request Headers 7. 复制以下三个参数: - accessToken - sign - timestamp 8. x-encode 不需要手动保存,脚本会在每次发请求前动态生成

    2. 保存认证信息

    如果使用浏览器自动化登录,认证信息会自动保存。

    如果手动获取,将认证信息保存到文件:

    mkdir -p ~/.config/shlibrary-seat-booking/profiles
    cat > ~/.config/shlibrary-seat-booking/profiles/default.json << 'EOF'
    {
      "accessToken": "你的accessToken",
      "sign": "你的sign",
      "timestamp": "你的timestamp"
    }
    EOF
    chmod 600 ~/.config/shlibrary-seat-booking/profiles/default.json
    

    注意:

  • 认证信息会失效,但接口没有提供稳定可读的明确过期时间
  • book_seat.js 会先探测登录态;如果认证来自 profile 文件且缺失或失效,会自动拉起 login.js
  • 如果接口返回 code 101 / 获取用户信息时出现异常,脚本也会按失效登录态处理
  • 是否“过期”以接口探测结果为准,不建议只靠本地时间戳人工判断
  • 不要把真实凭证提交到仓库或发给别人
  • 如果你需要管理多个账号,也可以按 profile 名称保存多个文件:

    ~/.config/shlibrary-seat-booking/profiles/default.json
    ~/.config/shlibrary-seat-booking/profiles/user1.json
    ~/.config/shlibrary-seat-booking/profiles/user2.json
    

    认证读取优先级是:

  • --auth-file:直接读取显式指定的单文件
  • --profile-dir + --profile:读取 /profiles/.json
  • 默认 profile 根目录 + --profile:读取 ~/.config/shlibrary-seat-booking/profiles/.json
  • 什么都不传:读取 ~/.config/shlibrary-seat-booking/profiles/default.json
  • 认证写入规则是:

  • 传了 --auth-file:登录成功后写回该文件
  • 传了 --profile-dir + --profile:写 /profiles/.json
  • 只传 --profile:写 ~/.config/shlibrary-seat-booking/profiles/.json
  • 什么都不传:写 ~/.config/shlibrary-seat-booking/profiles/default.json
  • 补充说明:

  • book_seat.js 会先探测登录态;如果 profile 文件缺失或登录态失效,会自动拉起 login.js
  • 3. 预约座位

    #### 预约座位

    统一使用 book 子命令:

    # 整天自动分配
    node ./scripts/book_seat.js \
      book --date 2026-03-24

    单时段自动分配

    node ./scripts/book_seat.js \ book --date 2026-03-24 --period 上午

    整天指定座位

    node ./scripts/book_seat.js \ book --date 2026-03-24 --area 南区 --seat-row 4 --seat-no 5

    单时段指定座位

    node ./scripts/book_seat.js \ book --date 2026-03-24 --period 下午 --area 南区 --seat-row 4 --seat-no 5

    脚本执行流程:

    1. 按优先级读取认证文件 2. 如果认证缺失或失效,自动拉起登录流程 3. 根据参数组合判断是自动分配还是指定座位、整天还是单时段 4. 如果是指定座位,先查询目标时段的可用座位 5. 如果座位可用,再提交预约 6. 输出预约成功或失败信息

    #### 系统自动分配

    如果你只关心时间段,不关心具体座位,可以让系统自动分配:

    # 预约3月22日上午,由系统自动分配座位
    node ./scripts/book_seat.js \
      book --date 2026-03-22 --period 上午
    

    自动分配模式的流程:

    1. 按优先级读取认证文件 2. 如果认证缺失或失效,自动拉起登录流程 3. 直接调用预约接口,请求系统分配可用座位 4. 输出预约成功或失败信息

    也支持按时段标签自动分配:

    node ./scripts/book_seat.js \
      book --date 2026-03-22 --period 上午
    

    如果要替另一个账号查预约:

    node ./scripts/book_seat.js \
      list --profile user1
    

    4. 查询已有预约

    如果你想先确认账号当前已经约了哪些时间段,可以直接查询:

    node ./scripts/book_seat.js list
    

    查询模式会:

    1. 按优先级读取认证文件 2. 如果认证缺失或失效,自动拉起登录流程 3. 调用"我的预约"接口 4. 按日期分组打印当前账号的预约记录 5. 展示每条记录的时间段、座位、预约状态、预约 ID 和是否可取消

    5. 查询整天公共可用座位

    如果你想先筛出“某一天全部时段都可用”的位置,可以直接查询。这里日期是必填参数,区域通过 --area 可选传入:

    node ./scripts/book_seat.js \
      availability --profile user1 --date 2026-03-20 --area 北区 西区 东区
    

    如果你不指定区域,脚本会自动扫描全部区域:

    node ./scripts/book_seat.js \
      availability --profile user1 --date 2026-03-20
    

    这个模式会:

    1. 读取对应 profile 的认证信息 2. 如果认证缺失或失效,自动拉起登录流程 3. 根据日期判断当天是 2 个时段还是 3 个时段 4. 扫描目标区域的所有排号和可用座位 5. 计算每个区域在当天全部时段的座位交集 6. 输出每个区域“所有时段都可用”的座位列表

    说明:

  • 可以通过 --area 传一个或多个区域,例如 --area 北区 西区 东区
  • 也可以传区域 ID:2 / 3 / 4 / 5
  • 如果不传区域,脚本会扫描全部区域
  • 周一会按 2 个时段求交集,其他日期按 3 个时段求交集
  • 这是只读查询,不会创建任何预约
  • 6. 取消预约

    如果你已经知道预约 ID,可以直接取消:

    node ./scripts/book_seat.js cancel --reservation-id 5187335
    

    取消模式会:

    1. 按优先级读取认证文件 2. 如果认证缺失或失效,自动拉起登录流程 3. 调用取消预约接口 4. 输出成功或失败结果

    更稳的使用顺序通常是:

    1. 先执行 list 2. 找到目标记录的 预约ID 3. 再执行 cancel --reservation-id [预约ID]

    时段映射规则

    当前脚本按业务规则使用固定 mapping:

  • 周一
  • - 下午 -> 13:45:00-16:45:00 - 晚上 -> 17:00:00-20:30:00 - 上午 -> 不可用
  • 周二到周日
  • - 上午 -> 09:15:00-12:45:00 - 下午 -> 13:00:00-16:30:00 - 晚上 -> 16:45:00-20:15:00

    如果图书馆后续调整了开放时段,这部分规则也需要同步更新。

    整天预约顺序

    当使用整天预约模式时,脚本会按这个顺序逐段尝试:

    1. 下午 2. 晚上 3. 上午

    这是一种 best-effort 策略:

  • 某一段失败不会中断其他时段
  • 最后会统一汇总成功和失败结果
  • 每个时段提交后会等待约 1 秒,再继续下一段,尽量降低"请勿重复提交"这类频控问题
  • 自动重试策略

    当前脚本对部分临时性失败做了短重试:

  • 当接口返回 系统拥挤,请稍后再试
  • 预约和取消都会自动重试
  • 默认最多重试 3
  • 每次重试间隔约 1.5
  • 像这些明确的业务失败不会自动重试:

  • 座位已约满
  • 该时间段有其他预约
  • 目标座位不可用
  • 区域 ID 对照

  • 2: 东区
  • 3: 西区
  • 4: 北区
  • 5: 南区
  • 预约规则

  • 放号时间: 每日12:00开放从当天算起第7天的座位预约
  • 签到时间: 预约开始时间后15分钟内必须扫码签到
  • 取消预约: 可在"我的预约"中提前取消
  • 违规处理: 3次违规将暂停预约权限30天
  • 参考资料

  • API文档: 详见 references/api_reference.md
  • 预约规则: https://yuyue.library.sh.cn/notice/seatAllNotice.html
  • 故障排除

    认证失败

  • 检查认证信息是否过期
  • 检查 accessTokensigntimestamp 三个字段是否都存在
  • 重新登录获取新的认证信息
  • 如果返回 code 101 / 获取用户信息时出现异常,也按登录态失效处理
  • 座位不可用

  • 该座位可能已被他人预约
  • 脚本会打印当前可用座位列表,可改约其他座位
  • 系统自动分配失败

  • 如果接口返回"该时间段有其他预约",说明当前账号在同一时段已有预约,不能重复预约
  • 如果接口返回无可用座位,需要更换时间段再试
  • 查询已有预约失败

  • 检查认证信息是否过期
  • 如果接口返回登录页或非 JSON,通常是认证失效
  • 如果接口返回 code 101 / 获取用户信息时出现异常,通常也需要重新登录
  • 重新抓取 accessTokensigntimestamp 后重试
  • 取消预约失败

  • 检查该 预约ID 是否存在
  • 确认该记录当前 可取消: 是
  • 如果接口提示状态不允许取消,说明该预约可能已签到、已过期或已取消
  • 接口返回非 JSON 或 HTTP 错误

  • 这通常表示认证失效、请求被拦截、或接口返回了登录页/错误页
  • 先重新获取认证信息,再重试
  • 必要时参考 references/api_reference.md 核对请求参数
  • API调用失败

  • 检查网络连接
  • 确认认证信息正确
  • 查看脚本输出中的 HTTP 状态码、响应片段和错误信息