Skip to content
EnderAvaritiaPublic

About

自己练手的机器人

Resources

Stars

3 stars

Watchers

0 watching

Forks

Latest commit

 

History

242 Commits

Folders and files

Repository files navigation

foxMeido

基于 NoneBot2 的 QQ 机器人,主要功能是查询 Steam 相关数据。

快速开始

安装依赖

pip install requests beautifulsoup4 playwright httpx lxml
playwright install chromium

# NoneBot 插件
nb plugin install nonebot-plugin-alconna
nb plugin install nonebot_plugin_apscheduler

配置

cp .env.example .env

编辑 .env,配置 NapCat 连接信息。详见下方 配置。

运行

nb run

配置

所有配置通过 .env 文件设置(已 gitignore)。参考 .env.example。

必需(NapCat / OneBot V11)

通过 WebSocket 连接 NapCat(或其他 OneBot V11 实现),无需 QQ 开放平台凭证。

变量 说明
DRIVER NoneBot 驱动,必须包含 ~websockets 以支持 ws 连接
ONEBOT_WS_URLS NapCat WebSocket 地址,格式 ["ws://ip:port"]
ONEBOT_API_ROOTS NapCat HTTP API 地址,格式 {"bot_qq": "http://ip:port/"}
HOST 监听地址,默认 127.0.0.1
PORT 监听端口
COMMAND_START 指令前缀,默认 [""](无前缀)

.env 示例:

DRIVER=~httpx+~websockets
ONEBOT_API_ROOTS={"2326291391": "http://127.0.0.1:26657/"}
ONEBOT_WS_URLS=["ws://192.168.10.14:26657"]
HOST=127.0.0.1
PORT=26657
COMMAND_START=[""] 

数据库(可选)

登记游戏领取记录的后端数据库,两种后端可选:SQLite(默认)或 NocoDB。

不用数据库功能?可删除 plugins/db/ 目录,但需同时删除依赖它的命令插件(bind / get / remain / report / unfinished / unreported / queryWishlist / probe / calendar / wish;curator_monitor 需关闭其中的数据库同步)。Steam 查询、price 比价、截图、代理等功能不需要数据库——配置读取已解耦到 plugins/config.py,删除后不受影响。

变量 默认值 说明
DB_BACKEND 智能默认 后端选择:sqlite(默认)或 noco。不设置时若检测到 NOCO_TOKEN 已配置则默认 noco,否则 sqlite
SQLITE_PATH data/db/foxmeido.db SQLite 数据库文件路径(仅 sqlite 后端使用,首次使用自动建表)

NocoDB 后端(DB_BACKEND=noco 时需自行部署 nocodb/nocodb):

变量 默认值 说明
NOCO_URL https://127.0.0.1:52533/api/v2/tables NocoDB API 地址
NOCO_TOKEN — API Token(必填)
NOCO_ACCOUNT_TABLE — account 表格 ID
NOCO_RECORD_TABLE — record 表格 ID
NOCO_REMAIN_TABLE — remain 表格 ID
NOCO_CHECK_REMAIN true get 指令是否检查 remain 表剩余副本数;false 时跳过检查直接登记
NOCO_WISHLIST_TABLE — wishlist 表格 ID
NOCO_VERIFY_SSL false 是否验证 SSL(国内自建通常用自签名证书,默认关闭)

后端迁移:两个后端可随时切换,数据迁移用 scripts/migrate_db.py:

# NocoDB → SQLite(换 sqlite 后端前执行)
python scripts/migrate_db.py --from noco --to sqlite

# SQLite → NocoDB(回迁)
python scripts/migrate_db.py --from sqlite --to noco

数据库抽象层(插件开发用):sqlite / noco 各自实现为独立后端指令,统一继承 DatabaseBackend 抽象基类。命令插件通过 get_backend() 获取当前配置(DB_BACKEND)对应的后端实例,只依赖抽象接口,不感知具体后端。配置读取统一在 plugins/config.py(全局配置中心,与可选的 db 文件夹解耦):

from plugins.db import get_backend
from plugins import config as cfg  # 全局配置中心(DB_BACKEND / SQLITE_PATH 等)

backend = get_backend()  # DB_BACKEND=sqlite → SqliteBackend,DB_BACKEND=noco → NocoBackend

# where: [(field, op, value), ...],op ∈ {eq, gt, ne},value=None 表示 NULL 判断
rec = backend.get_record("account", [("account", "eq", "123456")])
rows = backend.get_records("remain", [("canBeClaimed", "gt", 0)], sort="created_at")
rec = backend.create_record("wishlist", {...})
rec = backend.update_record("records", 42, {"report": 1})

逻辑表名:account / records / remain / wishlist。 返回约定:查询为空返回 "",失败返回 {"error": ...},列表返回 {"list": [...], "pageInfo": {"totalRows": n}}。 表结构参考 plugins/db/createTables.sql(sqlite 自动建表同源)。

代理(可选)

国内访问 Steam 需要代理转发。只设 HTTP_PROXY 即可,HTTPS_PROXY 自动同步。

变量 默认值 说明
HTTP_PROXY — 代理地址,如 http://127.0.0.1:7890。不设则不走代理
HTTPS_PROXY — 跟随 HTTP_PROXY,通常无需单独设置

Steam(可选)

变量 说明
STEAM_COOKIE Steam 商店页面 Cookie,wish 功能和热门标签提取需要。从浏览器访问 store.steampowered.com → F12 → 复制请求头 Cookie: 整行。格式:sessionid=xxx; steamLogin=xxx; ...
STEAM_CC 目标国家/地区码,控制 Steam API 返回的货币和区域定价。如 cn → 人民币、us → 美元、jp → 日元。留空则按出口 IP 自动决定
PRICE_REGIONS price 命令查询的区域列表,逗号/空格分隔可多个。如 cn,us,jp。留空则用默认集合:cn,us,jp,kr,hk,tw,sg,gb,de,fr,br,au,ca
CURATOR_ID Steam 鉴赏家 ID(unreported 功能需要)

price 多区域比价:

price 1091500
比价 https://store.steampowered.com/app/1091500/Cyberpunk_2077/

输出按折合人民币升序排列,自动标出最低价区:

Cyberpunk 2077(AppID 1091500)各区现价,按折合人民币升序
US 美国  $19.99 ≈¥141.63 (-50%,原价 $39.99)
JP 日本  ¥3,280 ≈¥160.90
CN 中国  ¥ 298.00
无价格(锁区/未上架/网络异常):RU 俄罗斯
最低:US 美国 ¥141.63

说明:外币统一用实时汇率(open.er-api.com,基准人民币)折算便于比较;结果在内存缓存 15 分钟;区域码不区分大小写,重复自动去重。

Playwright(可选)

Playwright 用于 Steam 页面截图(steamGoods、pub 等命令)。

变量 默认值 说明
PLAYWRIGHT_ENABLED true 是否启用 Playwright 截图。设为 false 时跳过 Playwright,游戏详情截图改用 Steam Store API 回落
PLAYWRIGHT_HEADLESS true 无头模式。设为 false 可在调试时看到浏览器窗口
PLAYWRIGHT_COOKIE_FILE — Playwright 格式的 Cookie 文件路径(JSON),用于登录态截图。参考 data/cookies/steam_playwright.json.example

获取 Playwright Cookie:

python scripts/get_steam_cookies.py

弹出浏览器 → 手动登录 Steam → 回车 → cookie 自动写入 data/cookies/steam_playwright.json。然后在 .env 中添加:

PLAYWRIGHT_COOKIE_FILE=data/cookies/steam_playwright.json

Playwright 的 cookie 格式与 STEAM_COOKIE(requests 用)不通用,需要单独的文件。STEAM_COOKIE 用于 wish 命令,PLAYWRIGHT_COOKIE_FILE 用于截图功能。

截图失败调试:

截图遇到超时或页面加载失败时,系统会自动将当前页面可见内容保存为 PNG 快照,存放到 logs/failed_screenshot_*.png。文件名包含失败来源和时间戳,可用于排查页面结构变化或网络问题。

鉴赏家副本监控(可选)

监控 Steam 鉴赏家后台的待处理游戏副本邀请,有新副本到达时通过 QQ 群消息(和/或 ntfy)推送通知。

变量 默认值 说明
CURATOR_COOKIE_FILE — (推荐) Playwright 格式的 Cookie 文件路径(JSON),通过 python scripts/get_curator_cookies.py 获取。bot 运行时通过 Playwright 加载,session 维持更久
CURATOR_COOKIE — (旧方式/降级) 静态 Cookie 字符串,从浏览器复制。仅在未设置 CURATOR_COOKIE_FILE 时使用
CURATOR_ENABLED false 是否启用每日定时检查
CURATOR_NAME 自动探测 鉴赏家显示名称。不设则自动从 Steam 页面抓取
CURATOR_NOTIFY_GROUP — 每日定时推送的目标群号
CURATOR_NOTIFY_USER — 每日定时推送的目标 QQ 号(可选,与 GROUP 可同时设置)
CURATOR_CHECK_TIME 09:00 每日定时检查时间,多个用逗号分隔,如 09:00,15:00,21:00
CURATOR_NTFY_TOPIC — ntfy topic,设了则额外推送到手机

推荐设置方式:

# 1. 运行获取脚本(弹出浏览器 → 登录 Steam → 导航到鉴赏家后台 → 回车)
python scripts/get_curator_cookies.py

# 2. 在 .env 中添加:
CURATOR_COOKIE_FILE=data/cookies/curator_playwright.json
CURATOR_ID=你的鉴赏家ID

命令:

命令 说明
pending 手动触发一次检查,结果发送到当前群。有今日新到游戏时额外输出 📋 今日新到游戏 列表
pending init 建立历史基线:抓取当前所有待处理游戏并标记为历史入库(不推送、不计入「今日新到」),用于首次接入监控时防止积压库存刷屏
pending init force 数据库已有记录时强制重建基线(不给 force 会被拦截,避免把真正的新到游戏误设为历史)
pending test 发送测试推送(QQ 消息 + ntfy 如有配置)

自动首跑:若数据库从未初始化过(SQLite meta 表无 initialized 标记),普通 pending 与定时检查也会自动走上述「静默基线」路径,不会刷屏;已有历史数据的旧库视为已初始化,不受影响。基线初始化时是否把库存同步进 remain 台账,沿用现有 CURATOR_SYNC_REMAIN 开关。

消息格式:

📦 鉴赏家名 新增待处理副本:        ← 本次新增的游戏
  🆕 游戏A(123456)(1 个副本)

📋 鉴赏家名 今日新到游戏:           ← 今天所有新到游戏(含本次新增)
  📅 游戏A(123456)(1 个副本)
  📅 游戏B(789012)(2 个副本)

💡 共 5 款游戏待处理

日志输出:

每次检查在后台输出一条日志,三种情况:

鉴赏家检查完成: 待处理 5, 游戏 7 款, 新增 2, 累计 7
最新: 霍格沃茨之遗             ← 有新增时
鉴赏家检查完成: 待处理 3, 游戏 3 款, 新增 0, 累计 7
无新增                          ← 有游戏但无变化
鉴赏家检查完成: 待处理 0, 游戏 0 款, 新增 0, 累计 7
探测结果为空                     ← Cookie 过期或页面抓取失败

数据库修复:

如果因版本升级导致 📋 今日新到 显示了所有历史游戏(而非仅当天),执行:

python scripts/fix_curator_db.py

这会重置 first_seen_at 错误记录,仅保留真正当天入库的游戏。

注:pending init force 可在 bot 内完成同类重置,无需停服执行脚本。

累计 为 SQLite 中累积的唯一游戏总数(不会回缩)。

Cookie 过期提示:

  • 使用 CURATOR_COOKIE_FILE(Playwright 方式)时,如果 cookie 过期,系统会自动检测登录页面,提示 ❌ CURATOR_COOKIE_FILE 已过期,请重新运行 python scripts/get_curator_cookies.py
  • 使用 CURATOR_COOKIE(旧方式)时,同样会检测登录页并给出提示,建议迁移到 Playwright 方式

消息表情回复(可选)

收到消息后立即添加 QQ 表情回应(如 ✅),类似 frontier 的 send_group_message_reaction 模式。仅 NapCat/OneBot V11 支持,不支持时自动忽略。

变量 默认值 说明
MESSAGE_REACTION_ENABLED false 是否启用表情回复
MESSAGE_REACTION_FACE_ID 32 QQ 表情 ID,详见常见 ID 表
MESSAGE_REACTION_AUTO_REMOVE false 处理结束后是否自动撤回表情

常见 QQ 表情 ID:

ID 视觉 推荐场景
32 ✅ 对勾 安全通过
26 ❌ 叉 拒绝/不通过
212 🤔 思考 处理中
351 👍 强 赞同/完成
324 👌 好的 收到/等待
319 🎉 庆祝 任务完成
0 😲 惊讶 —
14 🙂 微笑 —
13 😁 呲牙 —
67 ❤️ 爱心 —
107 ⭕ OK —
105 👍 爱你 —
101 🙏 抱拳 —
74 💩 便便 —

崩溃推送 ntfy(可选)

log_crash() 调用时会额外推送 ntfy 通知。可自建 ntfy 服务器。

变量 默认值 说明
CRASH_NTFY_SERVER https://ntfy.sh ntfy 服务器地址
CRASH_NTFY_TOPIC — ntfy topic,不设则不推送

自动拉取仓库更新(可选)

定时或手动执行 git pull,检测到新提交后自动重启机器人以加载新代码。

更新流程: 检测到更新后,机器人先把更新状态写入项目根目录的 .lock 标记文件,再发送「🔄 更新成功」提示。提示为尽力送达(best-effort):若 nb run 的自动重载恰好在拉取瞬间关闭了连接导致提示发送失败,不会报错——重启完成后会依据 .lock 自动补发「✅ 更新完成 + 本次提交列表」,保证用户一定能收到结果(群聊触发回发到该群,私聊触发回发到该用户私聊)。默认不主动退出进程 —— nb run 自带自动重载(reload),检测到代码文件变化后会优雅重启并加载新代码。

若以 --no-reload 运行或部署在生产环境(进程管理器托管),请设置 GIT_AUTO_PULL_FORCE_EXIT=true:拉取成功后会主动退出进程,由 GIT_AUTO_PULL_RESTART_CMD / 进程管理器 / 启动脚本接管拉起。

变量 默认值 说明
GIT_AUTO_PULL_ENABLED false 是否启用自动检查
GIT_AUTO_PULL_INTERVAL 30 间隔模式:每 N 分钟检查一次
GIT_AUTO_PULL_TIME 06:00 定时模式:每天检查时间
GIT_AUTO_PULL_SCHEDULE_TYPE both 调度类型:cron / interval / both
GIT_AUTO_PULL_NOTIFY_GROUP — 拉取结果通知的目标群号(可选)
GIT_AUTO_PULL_REMOTE origin 远程仓库名或 URL(如 origin 或 https://github.com/user/repo.git)
GIT_AUTO_PULL_GIT_PATH git git 可执行文件路径(绝对路径或仅文件名)
GIT_AUTO_PULL_RESTART_CMD — 自定义重启命令(仅在 FORCE_EXIT=true 时生效;如 systemctl restart foxmeido)
GIT_AUTO_PULL_FORCE_EXIT false 是否主动退出进程。默认 false:交给 NoneBot 自动重载;true:主动退出,由 RESTART_CMD / 进程管理器接管
GIT_AUTO_PULL_BRANCH — 目标分支(留空自动检测当前分支)

Steam Store API 参考

Steam 非官方 API store.steampowered.com/api/appdetails 的参数说明、返回格式、注意事项和常用货币对照表 → scripts/steam_store_api.md

命令

命令 别名 说明
id <appid/url> steam 查商店 steamGoods 查询游戏详情(名称、类型、热门标签、厂商、发行日期、价格、截图)
price <appid/url> 比价 查询多个区域的游戏价格比价(区域由 PRICE_REGIONS 配置,输出按折合人民币升序)
morepic <appid/url> 更多截图 发送游戏全部截图缩略图(Steam API screenshots.path_thumbnail)
pub <publisher> steamPublishers 查询发行商页面截图(?flavor=all_upcoming,即将推出列表)
find <关键字> 搜索steam游戏 交互式搜索 Steam 游戏,搜索结果选编号后显示详情(名称、类型、热门标签、语言、日期、发行商、价格、截图)
pending — 鉴赏家副本监控,手动触发检查;首次运行自动静默建立基线
bind — 将 Steam ID 绑定到 QQ 账号
get <游戏ID> [用户ID] — 登记游戏领取记录(可代他人登记)
remain <游戏ID> [份数] — 剩余份数登记 / 查询当前领取情况
wish <游戏ID> — 将游戏加入 Steam 愿望单
report <游戏ID> — 将指定游戏的记录标记为已报告
probe — 检测领取记录链接是否有效并更新提交时间
unfinished — 输出未完成(未提交评测)的记录
unreported — 输出未报告的游戏及用户
queryWishlist <游戏ID> queryWish qwish 查询愿望单记录
calendar cale 愿望单 冤枉单 任务 Steam 个人日历截图
finder <url> — 通用页面截图
update / pull — 手动触发 git pull,检测到更新后自动重启机器人
update force — 强制拉取(丢弃本地未提交更改)后重启
ping — 心跳测试
help — 显示帮助

Steam 商店链接会自动触发查询(如发送 https://store.steampowered.com/app/3251240)。

错误日志

运行中的异常自动写入 logs/ 目录,每次错误一个时间戳文件。

  • 文件格式:error_<时间戳>.log 或 crash_<时间戳>.log
  • 内容:[时间] [来源] 描述 + 异常堆栈
  • 截图失败快照:failed_screenshot_<来源>_<时间戳>.png(Playwright 截图失败时自动保存的页面快照,用于排查页面加载问题)

项目结构

foxMeido/
├── .env.example          # 配置模板
├── pyproject.toml        # NoneBot 项目配置
├── scripts/              # 工具脚本
│   ├── get_steam_cookies.py    # 获取 Playwright 格式的 Steam cookie
│   ├── get_curator_cookies.py  # 获取鉴赏家后台 Playwright cookie
│   ├── fix_curator_db.py       # 修复 curator 数据库 first_seen_at 记录
│   ├── migrate_db.py           # NocoDB ↔ SQLite 双向迁移
│   ├── steam_store_api.md      # Steam Store API 参考(appdetails / 多区比价用)
│   ├── steam_reviews.md         # steam_reviews.py 使用说明
│   └── steam_reviews.py        # 提取 Steam 用户评测中的鉴赏家链接 → [`doc`](scripts/steam_reviews.md)
├── data/                 # 运行时数据(gitignore)
│   ├── cookies/          #   Playwright cookie 文件
│   │   └── steam_playwright.json.example  #   cookie 格式模板
│   └── db/               #   SQLite 数据库文件
├── logs/                 # 错误日志(自动创建,gitignore)
└── plugins/
    ├── env_utils.py        # 环境变量读取、代理配置(通用工具)
    ├── config.py           # 全局配置中心(读取 .env:DB/Steam/代理/PRICE_REGIONS)
    ├── steam_utils.py      # Steam 通用工具
    ├── curator_monitor.py# Steam 鉴赏家副本监控
    ├── finder.py         # 通用页面截图
    ├── help.py           # 帮助命令
    ├── ping.py           # 心跳测试
    ├── steamFinder.py    # Steam 游戏详情查询
    ├── steamFinderAuto.py# Steam 链接自动触发查询
    ├── steamPublisherFinder.py    # 发行商页面查询
    ├── steamPublisherFinderAuto.py# 发行商链接自动触发
    ├── steamSearcher.py  # Steam 游戏搜索
    ├── price.py          # 多区域价格比价命令
    ├── playwright_utils.py # 共享 Playwright 工具
    ├── auto_pull.py        # 自动拉取仓库更新(定时 + 手动命令)
    ├── message_reaction.py # 表情回复模块(核心函数 + 自动钩子)
    ├── error_logger.py     # 错误日志模块(全模块共用)
    ├── bind.py           # 登记 Steam ID(绑定账号)
    ├── get.py            # 登记游戏领取记录
    ├── wish.py           # 愿望单登记
    ├── remain.py         # 剩余份数登记/查询
    ├── probe.py          # 检测领取记录链接是否有效
    ├── report.py         # 标记游戏已报告
    ├── unfinished.py     # 输出未完成记录
    ├── unreported.py     # 输出未报告记录
    ├── queryWishlist.py  # 查询愿望单记录
    ├── calendar.py       # Steam 个人日历截图
    └── db/                 # 数据库抽象层(sqlite / noco 双后端指令)
        ├── __init__.py     #   抽象层:DatabaseBackend 接口 + get_backend() 工厂
        ├── base.py         #   DatabaseBackend 抽象基类(接口定义)
        ├── sqlite.py       #   SqliteBackend 指令(SQLite 后端实现)
        ├── noco_backend.py #   NocoBackend 指令(NocoDB 后端实现)
        └── createTables.sql#   4 张表结构参考(sqlite 自动建表同源)

TODO

  • wish功能每隔一段时间自动探测游戏何时发售
  • 获取领取记录,用于核对

About

自己练手的机器人

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages