为什么突然想写这个?
昨天晚上,我跟朋友约好了一起看球赛,结果临时加班,只能盯着手机刷比分,我一边写代码一边想——“今晚比赛几比几了?”这个问题,能不能用我手头的Golang快速搞定呢?
说干就干,我打开编辑器,开始写一个能查询实时比分的小工具,整个过程挺有意思的,分享给你。
先搞个最简单的版本
我一开始想得很简单:定义一个结构体,存比赛信息,然后手动输入比分。
package main
import "fmt"
type Match struct {
TeamA string
TeamB string
ScoreA int
ScoreB int
}
func main() {
match := Match{
TeamA: "中国队",
TeamB: "日本队",
ScoreA: 2,
ScoreB: 1,
}
fmt.Printf("今晚比赛几比几? %s %d : %d %s\n",
match.TeamA, match.ScoreA, match.ScoreB, match.TeamB)
}
跑了一下,输出:“今晚比赛几比几? 中国队 2 : 1 日本队”。
嗯,够直接,但不够实用。
需求升级:怎么拿到实时数据?
手动输入肯定不行,我需要从网上抓真实数据,这时候Golang的net/http包就派上用场了。
抓数据的基本姿势
resp, err := http.Get("https://api.sportsdata.com/v1/scores")
if err != nil {
log.Fatal("请求失败:", err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
这里有个坑——很多体育API需要API Key,我找了个免费的公开接口试了试,发现返回的是JSON格式。
解析JSON,别手写
Golang标准库的encoding/json足够用了,我定义了一个结构体来映射API返回的数据:
type ApiMatch struct {
HomeTeam string `json:"home_team"`
AwayTeam string `json:"away_team"`
HomeScore int `json:"home_score"`
AwayScore int `json:"away_score"`
Status string `json:"status"`
}
注意字段后面的json:"..."标签,这是告诉解析器怎么对应JSON的key。
完整抓取流程
我写了个函数,专门拿来“今晚比赛几比几”这个问题的答案:
func GetLiveScore(apiURL string) (*ApiMatch, error) {
client := &http.Client{Timeout: 10 * time.Second}
req, _ := http.NewRequest("GET", apiURL, nil)
req.Header.Set("User-Agent", "Mozilla/5.0")
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("网络请求失败: %v", err)
}
defer resp.Body.Close()
var match ApiMatch
if err := json.NewDecoder(resp.Body).Decode(&match); err != nil {
return nil, fmt.Errorf("解析失败: %v", err)
}
return &match, nil
}
写到这里我发现一个问题: 不同体育赛事的API返回格式不一样,足球比分和篮球比分的字段可能完全不同。
灵活处理:让代码适应不同赛事
我决定用接口(interface)来抽象:

type ScoreProvider interface {
GetScore() (string, error)
GetMatchInfo() string
}
然后分别实现足球、篮球、甚至电竞的查询器:
| 赛事类型 | 实现结构体 | 关键字段 |
|---|---|---|
| 足球 | FootballScore |
home_team, away_team, home_goals, away_goals |
| 篮球 | BasketballScore |
team_home, team_away, points_home, points_away |
| 电竞 | EsportsScore |
side_a, side_b, score_a, score_b |
这样不管用户问“今晚比赛几比几”,我都能根据比赛类型返回正确格式。
具体实现片段
拿足球为例:
type FootballScore struct {
HomeTeam string
AwayTeam string
HomeGoal int
AwayGoal int
Minute int
}
func (f *FootballScore) GetScore() (string, error) {
return fmt.Sprintf("%s %d:%d %s (第%d分钟)",
f.HomeTeam, f.HomeGoal, f.AwayGoal, f.AwayTeam, f.Minute), nil
}
调用的时候:
result, _ := footBallProvider.GetScore()
fmt.Println("今晚比赛几比几?", result)
// 输出:巴西 2:0 阿根廷 (第78分钟)
加个缓存,别频繁刷接口
如果用户每分钟都在问“今晚比赛几比几”,每次都请求API,一是慢,二是可能被限流。
我用sync.Map做了一个简单缓存:
var cache sync.Map
func CachedGetScore(provider ScoreProvider, key string) (string, error) {
if val, ok := cache.Load(key); ok {
return val.(string), nil
}
score, err := provider.GetScore()
if err == nil {
cache.Store(key, score)
// 30秒后自动过期
time.AfterFunc(30*time.Second, func() {
cache.Delete(key)
})
}
return score, err
}
这样,30秒内的重复查询直接返回缓存结果,快很多。
命令行版本:最直接的用法
我写了个简单CLI,支持查询参数:
go run main.go --sport=football --team=巴萨
内部逻辑是:
- 解析命令行参数(用
flag包) - 根据
sport参数选择对应的ScoreProvider - 调用
CachedGetScore获取结果 - 打印“今晚比赛几比几:XXX”
代码大概这样:
func main() {
sport := flag.String("sport", "football", "体育项目")
team := flag.String("team", "", "球队名称")
flag.Parse()
provider := GetProvider(*sport)
if provider == nil {
log.Fatal("暂不支持该体育项目")
}
result, err := CachedGetScore(provider, *team)
if err != nil {
log.Fatal("获取比分失败:", err)
}
fmt.Printf("今晚比赛几比几? %s\n", result)
}
实际跑起来的效果
我用一个测试API试了一下(为了避免暴露真实接口,这里用mock数据):
// 模拟英超数据
mockProvider := &FootballScore{
HomeTeam: "曼联",
AwayTeam: "利物浦",
HomeGoal: 1,
AwayGoal: 1,
Minute: 65,
}
运行程序,输出:
今晚比赛几比几? 曼联 1:1 利物浦 (第65分钟)
朋友看到消息回我:“我去,真的假的?我刚打开电视,真是1比1!”
有意思的是,当我问他“今晚比赛几比几”时,他反而问我“你怎么知道的?”
一些坑和教训
写这个工具踩了几个坑:
- 时区问题:API返回的时间是UTC,比赛时间可能是北京时间,转换时区搞错了
- JSON字段大小写:Go结构体字段要大写才能导出,JSON标签要写小写对应
- HTTP超时:不加超时的话,网络慢时会卡死
解决方案:
- 时间用
time.LoadLocation("Asia/Shanghai")处理 - 结构体字段首字母大写,JSON标签用小写
- 创建HTTP客户端时设置
Timeout
扩展思路:支持更多查询方式
如果觉得命令行不够方便,还可以:
- Web服务版:用
net/http暴露API,浏览器输入localhost:8080/score?team=皇马就能看到“今晚比赛几比几” - Telegram机器人:用
go-telegram-bot-api库,群聊里发/score就自动回复 - 桌面通知:比赛比分变化时,系统弹出通知
我试了Web版,一个函数搞定:
http.HandleFunc("/score", func(w http.ResponseWriter, r *http.Request) {
team := r.URL.Query().Get("team")
provider := GetProvider("football")
result, _ := provider.GetScore()
fmt.Fprintf(w, "今晚比赛几比几? %s", result)
})
http.ListenAndServe(":8080", nil)
代码组织和优化
随着功能增多,我重构了项目结构:
scores/
├── main.go
├── providers/
│ ├── football.go
│ ├── basketball.go
│ └── esports.go
├── cache/
│ └── cache.go
└── utils/
└── time.go
每个文件职责清晰,main.go只负责入口和参数解析。
真的有人用这个吗?
写完之后我把它分享到技术群里,有个老哥说:“我老婆天天问我今晚比赛几比几,我打算把这个做成智能音箱的技能。”
我想了想,Golang编译成二进制文件体积小、运行快,确实适合跑在树莓派这类设备上。
另一个群友说:“你这个比那些广告满天飞的比分App清爽多了。”
对了,有个小细节
我发现自己写的这个工具用起来最顺手的地方不是查比分,而是批量查询——比如欧洲杯期间,同时查5场比赛的比分。
写个循环:
matches := []string{"法国vs德国", "葡萄牙vs匈牙利", "西班牙vs瑞典"}
for _, m := range matches {
result := GetScoreByMatch(m)
fmt.Printf("今晚比赛几比几? %s: %s\n", m, result)
}
输出:
今晚比赛几比几? 法国vs德国: 1:0
今晚比赛几比几? 葡萄牙vs匈牙利: 3:0
今晚比赛几比几? 西班牙vs瑞典: 0:0
比手动刷网页快太多了。
最后
其实写这个小工具,最开始就是因为我懒得每次都去搜“今晚比赛几比几”,用Golang写完之后,不仅解决了自己的问题,还发现可以不断扩展——从支持更多赛事,到加缓存优化,再到做Web界面。
技术这东西,有时候不就是为了解决这种“懒”吗?
我现在每天下班前跑一下自己的小工具,看看喜欢的球队比分,朋友问我“今晚比赛几比几”,我直接回一句“等我跑一下代码”,然后两秒后发截图过去。
还挺酷的。
(如果你也想写一个,建议从最简单的开始,别一上来就想搞完美,先跑起来再说。)
本文来自作者[kyadmin]投稿,不代表678体育 - 全网热门体育赛事高清直播平台立场,如若转载,请注明出处:http://www.yuanlikao.com/nba/981.html
评论列表(4条)
我是678体育 - 全网热门体育赛事高清直播平台的签约作者“kyadmin”!
希望本篇文章《今晚比赛几比几?用Golang写一个实时比分查询小工具》能对你有所帮助!
本站[678体育 - 全网热门体育赛事高清直播平台]内容主要涵盖:678体育,678体育官网,678赛事直播
本文概览:为什么突然想写这个?昨天晚上,我跟朋友约好了一起看球赛,结果临时加班,只能盯着手机刷比分,我一边写代码一边想——“今晚比赛几比几了?...