说实话,我一开始用Golang写NBA季后赛数据统计的时候,纯粹是被逼的,当时朋友扔给我一个Excel,里面密密麻麻全是今年季后赛的球员数据——得分、篮板、助攻、命中率……他说你帮我整理一下,我想看约基奇和恩比德到底谁更强,我一看那Excel,眼睛都花了,于是我想,干脆写个程序,直接抓数据、算统计、输出报表,一步到位。
为什么是Golang?这不是篮球专栏吗?
别急,听我慢慢说,你可能觉得用Python或者R做数据分析更常见,但Golang有几个点真的让我上头,首先它够快,编译后就是个二进制文件,跑起来嗖嗖的,其次它并发处理能力强,你要同时拉取好几个网站的数据,goroutine一开,根本不用操心线程问题,而且Go的语法干净得像库里的三分球——没有花里胡哨的继承、重载,写起来特别舒服。
我记得有一次我要从三个不同的数据源(比如Basketball-Reference、ESPN、NBA官网)抓取同一场比赛的统计,要是用Python,requests一个一个发,还得考虑超时和重试,用Go的话,直接开三个goroutine,配合sync.WaitGroup等待所有请求完成,数据一下子就收齐了,那感觉就像看利拉德读秒绝杀,一气呵成。
数据从哪儿来?别跟我说手动输入
说到数据源,这事儿其实挺讲究,NBA官方确实有API,但需要开发者认证,有点麻烦,我一般用Basketball-Reference的公开页面,直接解析HTML表格,还有ESPN的统计页面,结构也挺规整。NBA.com的API虽然官方不公开,但有人破解了地址,也能用。
但我要提醒你,爬数据这事儿得温柔点,别每秒发几十个请求,人家服务器也不是铁打的,Go里你可以用time.Sleep或者time.Ticker来控制请求频率,比如每两秒发一个,我吃过一次亏,没加限速,IP直接被封了24小时,那叫一个憋屈。
核心代码:一个球员数据统计的结构体
先别着急写爬虫,我们得先把数据结构理清楚,在Go里面,结构体就是一切的基础,我一般这么定义:
type PlayerStats struct {
Name string `json:"name"`
Team string `json:"team"`
GP int `json:"gp"` // 出场次数
MPG float64 `json:"mpg"` // 场均时间
PPG float64 `json:"ppg"` // 场均得分
RPG float64 `json:"rpg"` // 场均篮板
APG float64 `json:"apg"` // 场均助攻
SPG float64 `json:"spg"` // 场均抢断
BPG float64 `json:"bpg"` // 场均盖帽
FGPercent float64 `json:"fg_percent"` // 投篮命中率
ThreePercent float64 `json:"three_percent"` // 三分命中率
FTPercent float64 `json:"ft_percent"` // 罚球命中率
}
你看,这结构体把球员最关键的季后赛统计全包进去了,有了它,不管是从哪个网站来的数据,都能映射到这个结构体里,而且Go的encoding/json包特别好用,你要输出JSON的话,直接json.Marshal就完事了。
抓取数据:别怕HTML,用goquery就行
解析HTML这事儿,Go生态里有个叫goquery的库,用法跟jQuery似的,比如要从Basketball-Reference抓2024季后赛的球员数据,我可以这么干:
doc, err := goquery.NewDocument("https://www.basketball-reference.com/playoffs/NBA_2024_per_game.html")
if err != nil {
log.Fatal(err)
}
var players []PlayerStats
doc.Find("table#per_game_stats tbody tr").Each(func(i int, s *goquery.Selection) {
// 解析每一列的数据
name := s.Find("td[data-stat='player'] a").Text()
team := s.Find("td[data-stat='team_id'] a").Text()
gp := s.Find("td[data-stat='g']").Text()
// ... 继续解析其他列
})
真实情况会比这个复杂一点,比如有些行是合并的,有些数据是空的,你还得做空值处理,Go的strconv包提供了ParseFloat和ParseInt,记得检查err。
有一回我爬到一个页面,发现有个球员的名字里面有特殊字符(比如带重音的字母),直接导致了string转义问题,后来我加了个strings.TrimSpace和strings.Replace,才算搞定,这种小事真是让人抓狂,但搞定了又特别有成就感。
数据清洗和计算:把"垃圾"数据变成"黄金"
原始数据拿下来之后,千万别直接用,我遇到过不少坑:有些网站把"DNP"(Did Not Play)显示成"0",但实际上应该排除;还有些球员只打了一场比赛,得了30分,场均数据高得离谱,但样本太小,反而会误导人。
我一般会设置一个最低出场次数,比如至少打4场季后赛,才纳入统计,在Go里,判断也很简单:
if stats.GP >= 4 {
// 加入有效数据列表
}
如果你要做进阶统计,比如PER(球员效率值)、TS%(真实命中率)或者WS(胜利贡献值),那就得自己写公式了,就拿真实命中率来说,公式是:TS% = PTS / (2 * (FGA + 0.44 * FTA)),看起来简单,但数据源里FGA和FTA的列名可能不一样,你得先映射好。
我写过一个小工具,自动计算这些进阶指标,然后跟原始数据一起输出,有个朋友看到我算出来的约基奇PER是31.2,当场就说"这数据牛逼,MVP就是他了",虽然他不一定懂PER是怎么算的,但数字摆在那儿,比什么感觉都靠谱。
输出报表:想要Excel表格?Go也能搞定
数据算好了,总得给人看吧,我一般输出两种格式:
控制台表格
用github.com/olekukonez/tablewriter库,直接打印出来:
+----------------+------+------+------+------+------+------+--------+--------+
| Player | Team | GP | PPG | RPG | APG | SPG | FGPct | 3PPct |
+----------------+------+------+------+------+------+------+--------+--------+
| Nikola Jokić | DEN | 12 | 28.5 | 13.2 | 9.8 | 1.5 | 0.586 | 0.412 |
| Joel Embiid | PHI | 10 | 27.8 | 10.5 | 5.6 | 1.2 | 0.532 | 0.378 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... |
+----------------+------+------+------+------+------+------+--------+--------+
HTML表格
有时候我想发到博客或者论坛上,HTML格式更友好,Go的html/template包可以渲染表格,配上一点CSS样式,看起来跟专业体育网站似的。
我不会用太复杂的模板语法,一般就是循环数据,一行行填充<tr>和<td>,对了,别忘了加<strong>标签高亮第一名的数据,这样读者一眼就能看到谁是佼佼者。
真实案例:我用Go分析了2024季后赛的数据
今年季后赛我盯上了掘金和森林狼的系列赛,那轮系列赛打得真是火星撞地球,我写了个小脚本,自动抓取两队所有球员的数据,然后算了个对位效率——也就是当一个球员在场上时,对方球员的进攻效率。

用到的方法其实挺费曼的:我把这事儿讲给一个完全不懂编程的哥们听,他说"你就告诉我,谁在场上时球队丢分最少?" 好,问题一下就简单了,我只需要计算每个球员的On/Off Court Diff。
用Go实现这个功能,关键是维护两个时间戳,从NBA的Play-by-Play数据里,我能抓取到每个球员的上场时间段,然后用这些时间段去匹配对方球队的得分,代码写得不算漂亮,但结果挺有意思的:杰登·麦克丹尼尔斯在场时,掘金每百回合少得15.2分,这种数据,光看场均得分根本看不出来。
把数据可视化?Go也赶时髦
光有表格还不够,有时候我想看趋势图,比如某个球员季后赛三分命中率的变化曲线,Go里有github.com/wcharczuk/go-chart这个库,可以直接生成PNG图表。
我画过一个约基奇季后赛每场的数据折线图,包括得分、助攻、篮板三条线,生成的时候加了个chart.ColorBlue和chart.ColorRed区分线条,说实话,画出来的图比Excel的默认样式好看多了,而且完全自动化,每次更新数据跑一遍脚本就行。
跟其他语言比,Go的优势在哪儿?
我不是说Go一定比Python好,但用Go做NBA数据统计有几个场景特别舒服:
- 当你需要频繁跑脚本:Go编译后的程序启动几乎不需要时间,Python还得加载解释器
- 当你需要并发抓取:goroutine内存消耗极小,一万个并发都没问题
- 当你需要部署到服务器:一个二进制文件丢上去就能跑,Python还得装包、配环境
如果你要做很复杂的统计建模,比如用贝叶斯预测季后赛胜率,那Python的库更丰富,但如果你就想快速拉数据、算统计、出报表,Go绝对是个好选择。
最后唠叨两句
写这个程序的初衷其实很朴素:我就是想看看自己喜欢的球员到底数据多好,但写着写着,发现这玩意儿还挺有用,我一个朋友是篮球评论员,他现在直接用我的Go程序生成数据,然后结合他的战术分析写文章,他说"你负责数字,我负责故事",配合得还挺好。
你要是也喜欢篮球,又刚学Go,不妨试试从这个项目入门,数据公开、规则清晰、结果直观,你每跑一次程序,看到那些球员的数据在屏幕上跳出来,就像看了一场微型比赛——有开局、有高潮、有胜负。
行,今天就聊到这儿,我得去改改程序了,2025季后赛快开始了,得提前把数据接口测一遍,万一NBA官网改了页面结构,我的代码又得翻车。
本文来自作者[kyadmin]投稿,不代表be365立场,如若转载,请注明出处:http://www.b22b.cn/nba/196.html
评论列表(4条)
我是be365的签约作者“kyadmin”!
希望本篇文章《用Golang搞定NBA季后赛数据统计,这事儿我能跟你聊一天》能对你有所帮助!
本站[be365]内容主要涵盖:be365,be365网站,be365网址,ball365体育,Be365排名
本文概览:说实话,我一开始用Golang写NBA季后赛数据统计的时候,纯粹是被逼的,当时朋友扔给我一个Excel,里面密密麻麻全是今年季后赛的球员...