snooker ⭐ · 项目介绍

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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
snooker/
├── scraper.py # 解析库:cuetracker head-to-head 页面解析
├── scrape_to_json.py # 全量爬 top 8(28 对)→ data/*.json
├── rescrape_top32.py # 重爬 top 32(496 对)
├── incremental_update.py # 旧增量(两两配对,已弃用但保留备查)
├── update_from_players.py# 新增量(球员赛季页,推荐)
├── enrich_players.py # snooker.org API 球员资料补全 → player_profiles.json
├── compare_data.py # 对比 data_old/ 与 data/ 差异
├── server.js # 本地服务:静态服务 + DeepSeek 代理(:8080)
├── index.html # 数据中心主页面(含 AI 问答 Tab)
├── explorer.html # 数据探索页
├── share.html # 分享页
├── lzstring.js / qrcode.js # LZ-String 压缩 / 二维码生成
├── players.json # top 球员列表(含 slug,用于构造爬取 URL)
├── data/ # 前端数据源 JSON
├── data_old/ # 历史快照(用于对比验证)
├── dist/ # 部署产物
├── cloudflare/ # Cloudflare Workers 部署子项目
├── snooker-data-center-wechat.md # 微信发布文
├── snooker_org_api_request.md # 向 snooker.org 申请 API 白名单邮件草稿
└── test_*.py # 各球员对验证测试

相关链接

补充:爬虫项目真正的难点是「持续更新」

爬一次数据不难,难的是半年后还能用。这个项目里我最在意的是增量更新这一层:

  • **incremental_update.py / rescrape_top32.py**:不做全量重爬。全量重爬对目标站点压力大、容易被封,而且已经抓过的历史数据没必要再动。增量更新是爬虫项目能不能长期活下去的分水岭。
  • enrich_players.py 是独立的清洗层:爬虫只负责「拿到原始字段」,补全、归一、关联关系放在清洗层。这两件事分开之后,目标站点改版时只需要改爬虫,清洗逻辑不用动。
  • share.html + qrcode.js + lzstring.js 这个组合比较有意思:把数据用 lz-string 压缩后编码进二维码,做出来的分享海报不需要后端接口也能还原出完整数据快照。对静态站部署(仓库里有 cloudflare/)来说这几乎是唯一可行的分享方案。
  • AI 问答只接 DeepSeek 一家:这是刻意的范围控制,不是技术限制。接多家意味着要处理多套计费、限流和回答风格,收益不抵复杂度。
  • 前端是原生 HTML/JS:数据中心这类以表格和图为主的页面,用框架反而增加负担。