snooker ⭐
本页由项目自动归档生成,源码与最新进展以 GitHub 仓库为准。
项目简介
斯诺克数据中心:用 Python 爬虫从 cuetracker.net 抓取职业球员对战数据(比赛、逐局比分、单杆得分),清洗为本地 JSON,再用 Node.js 本地服务 + 原生 HTML/JS 前端做数据展示,并支持基于 DeepSeek 的自然语言问答。线上部署在 Cloudflare Workers,自定义域名 snooker.hummingg.com。面向斯诺克球迷与需要可查询、可可视化、可 AI 问答的赛事数据场景。
技术栈
| 维度 | 技术 |
|---|---|
| 主要语言/框架 | Python 3(爬虫)+ Node.js(本地服务)+ 原生 HTML/JS(前端,无框架) |
| 关键依赖/库 | Python:requests、beautifulsoup4;Node.js:原生 http/https(无 Express);前端:lzstring.js(LZ-String 压缩)、qrcode.js(二维码) |
| 数据存储 | 本地 JSON(data/:players / tournaments / matches / frames / break_scores / player_profiles);线上托管到 Cloudflare Workers |
| 运行/部署方式 | 本地 node server.js(:8080);线上 cd cloudflare && wrangler deploy 部署到 Cloudflare Workers |
核心功能 / 亮点
- 数据解析库:
scraper.py提供 cuetracker head-to-head 页面解析(球员、比赛、局分、50+ 单杆),以纯函数形式供各爬虫复用,不直接读写数据库。 - 全量/重爬:
scrape_to_json.py爬 top 8 两两对战(C(8,2)=28 对);rescrape_top32.py爬 top 32(C(32,2)=496 对);均支持断点续爬、随机 User-Agent、指数退避重试、每对爬完即存盘。 - 增量更新:
incremental_update.py(旧,两两配对,数据成熟后抓不到新比赛且耗时长)与update_from_players.py(新,基于球员赛季页,推荐,约 15 分钟 / 178 人)。 - 资料补全与校验:
enrich_players.py用 snooker.org API 补球员国籍/出生年/排名冠军数/满分杆数;compare_data.py对比data_old/与data/差异。 - 本地服务:
server.js提供静态文件服务 +/api/chat代理 DeepSeek(端口 8080),含目录穿越防护,AI 问答 Key 存浏览器本地、服务端不存储。 - 前端数据中心:
index.html(逐局比分 + 单杆标注、球员档案、H2H 对战查询、排行榜、赛事浏览、AI 问答 Tab)、explorer.html(数据探索)、share.html(分享页)。 - 分享与压缩:
lzstring.js把数据压缩编码进二维码,qrcode.js生成分享海报,无需后端即可还原数据快照。 - 部署:
cloudflare/子项目用 Workers 托管静态资源 + 边缘/api/chat代理,自定义域名snooker.hummingg.com。
目录结构
1 | snooker/ |
相关链接
- GitHub 仓库:snooker
- 线上站点:snooker.hummingg.com
补充:爬虫项目真正的难点是「持续更新」
爬一次数据不难,难的是半年后还能用。这个项目里我最在意的是增量更新这一层:
- **
incremental_update.py/rescrape_top32.py**:不做全量重爬。全量重爬对目标站点压力大、容易被封,而且已经抓过的历史数据没必要再动。增量更新是爬虫项目能不能长期活下去的分水岭。 enrich_players.py是独立的清洗层:爬虫只负责「拿到原始字段」,补全、归一、关联关系放在清洗层。这两件事分开之后,目标站点改版时只需要改爬虫,清洗逻辑不用动。share.html+qrcode.js+lzstring.js这个组合比较有意思:把数据用 lz-string 压缩后编码进二维码,做出来的分享海报不需要后端接口也能还原出完整数据快照。对静态站部署(仓库里有cloudflare/)来说这几乎是唯一可行的分享方案。- AI 问答只接 DeepSeek 一家:这是刻意的范围控制,不是技术限制。接多家意味着要处理多套计费、限流和回答风格,收益不抵复杂度。
- 前端是原生 HTML/JS:数据中心这类以表格和图为主的页面,用框架反而增加负担。