黄河口马拉松成绩查询,用Golang写个查询器,其实没那么难

为啥我突然想写这个?前几天跑完黄河口马拉松,朋友圈都在晒成绩,我也想去官网查,结果那个页面加载慢得要命,想着自己好歹是个写Go的,干...

为啥我突然想写这个?

前几天跑完黄河口马拉松,朋友圈都在晒成绩,我也想去官网查,结果那个页面加载慢得要命,想着自己好歹是个写Go的,干脆写个小工具,命令行里嗖一下就能查到成绩,多带劲。

说实话,马拉松成绩查询这个需求挺简单的:输入参赛号,返回完赛时间、净成绩、枪声成绩、排名这些信息,但真要写出来,从HTTP请求到JSON解析,再到数据展示,一套流程跑下来,还挺锻炼人的。

第一步:找到数据接口

黄河口马拉松官网的成绩查询,本质上是向某个API发POST请求,我用浏览器开发者工具(F12)抓了一下,发现其实很简单:

黄河口马拉松成绩查询,用Golang写个查询器,其实没那么难

POST https://huanghekou.marathon.com/result/query
Content-Type: application/json
{
  "bib": "A12345",
  "type": "marathon"
}

返回的JSON结构大概长这样:

{
  "code": 200,
  "data": {
    "name": "张三",
    "bib": "A12345",
    "gun_time": "03:45:22",
    "net_time": "03:42:18",
    "rank": 128,
    "category": "男子全程",
    "category_rank": 45
  }
}

注意:实际接口可能加密,这里只是示意,但大多数国内马拉松查询接口,基本都这个套路

第二步:用Go写查询函数

直接上代码,不过我会边写边解释,你跟着走一遍就懂了。

建个结构体,存成绩数据

type MarathonResult struct {
    Name         string `json:"name"`
    Bib          string `json:"bib"`
    GunTime      string `json:"gun_time"`
    NetTime      string `json:"net_time"`
    Rank         int    `json:"rank"`
    Category     string `json:"category"`
    CategoryRank int    `json:"category_rank"`
}

这里用了JSON标签,方便直接把API返回的JSON映射过来,不写这玩意儿也行,但写了就省得手动拆字段了。

写查询逻辑

func QueryResult(bib string) (*MarathonResult, error) {
    url := "https://huanghekou.marathon.com/result/query"
    reqBody := map[string]string{
        "bib":  bib,
        "type": "marathon",
    }
    jsonData, _ := json.Marshal(reqBody)
    resp, err := http.Post(url, "application/json", bytes.NewBuffer(jsonData))
    if err != nil {
        return nil, fmt.Errorf("查询失败: %v", err)
    }
    defer resp.Body.Close()
    var result struct {
        Code int             `json:"code"`
        Data MarathonResult `json:"data"`
    }
    json.NewDecoder(resp.Body).Decode(&result)
    if result.Code != 200 {
        return nil, fmt.Errorf("服务器返回错误码: %d", result.Code)
    }
    return &result.Data, nil
}

这里有个坑:延迟加载,有些马拉松系统的查询接口,成绩是按批次开放的,你查太早了可能返回空数据,我一般等比赛结束2小时后才查。

第三步:命令行里跑起来

我想在终端直接输个参赛号就出结果,所以写了个命令行版本

func main() {
    fmt.Print("请输入参赛号: ")
    reader := bufio.NewReader(os.Stdin)
    bib, _ := reader.ReadString('\n')
    bib = strings.TrimSpace(bib)
    result, err := QueryResult(bib)
    if err != nil {
        fmt.Printf("出错了: %v\n", err)
        return
    }
    // 漂亮的表格输出
    fmt.Println("\n🏃 黄河口马拉松成绩单 🏃")
    fmt.Println("==============================")
    table := [][]string{
        {"姓名", result.Name},
        {"参赛号", result.Bib},
        {"枪声成绩", result.GunTime},
        {"净成绩", result.NetTime},
        {"总排名", strconv.Itoa(result.Rank)},
        {"组别", result.Category},
        {"组内排名", strconv.Itoa(result.CategoryRank)},
    }
    for _, row := range table {
        fmt.Printf("| %-10s | %s\n", row[0], row[1])
    }
}

你跑起来大概会看到这种效果:

请输入参赛号: A12345
🏃 黄河口马拉松成绩单 🏃
==============================
| 姓名       | 张三
| 参赛号     | A12345
| 枪声成绩   | 03:45:22
| 净成绩     | 03:42:18
| 总排名     | 128
| 组别       | 男子全程
| 组内排名   | 45

看着是不是挺像回事儿? 虽然界面有点粗,但自己用着顺手。

搞个更酷的:加个表格式输出

上面那个输出有点乱,咱们换成真正表格,用制表符对齐:

func printTable(results []MarathonResult) {
    fmt.Println("+----------+----------+----------+---------+------+------------+")
    fmt.Println("| 姓名     | 参赛号   | 枪声成绩 | 净成绩  | 排名 | 组别       |")
    fmt.Println("+----------+----------+----------+---------+------+------------+")
    for _, r := range results {
        fmt.Printf("| %-8s | %-8s | %-8s | %-7s | %-4d | %-10s |\n",
            r.Name, r.Bib, r.GunTime, r.NetTime, r.Rank, r.Category)
    }
    fmt.Println("+----------+----------+----------+---------+------+------------+")
}

这样查多个人成绩时,一列列排得整整齐齐,强迫症患者的福音

实际使用中的几个小坑

  1. 网络延迟:马拉松查询接口经常崩,建议加超时
client := &http.Client{Timeout: 10 * time.Second}
  1. 中文乱码:有些接口返回GBK编码,得转UTF-8
import "golang.org/x/text/encoding/simplifiedchinese"
decoder := simplifiedchinese.GBK.NewDecoder()
utf8Data, _ := decoder.Bytes(respBody)
  1. 查询次数限制:别写个死循环去刷,会被封IP,我一般间隔3秒查一次。

要不要做成Web服务?

如果你想让跑友也能用,可以加个HTTP接口

http.HandleFunc("/query", func(w http.ResponseWriter, r *http.Request) {
    bib := r.URL.Query().Get("bib")
    result, err := QueryResult(bib)
    if err != nil {
        json.NewEncoder(w).Encode(map[string]string{"error": err.Error()})
        return
    }
    json.NewEncoder(w).Encode(result)
})
http.ListenAndServe(":8080", nil)

然后别人就可以用浏览器访问 http://你的IP:8080/query?bib=A12345 来查成绩了。

不过千万别把这个服务部署到公网对外,一来版权问题,二来人家官方封你接口,自己本地玩玩就好。

黄河口马拉松的成绩查询,说到底就是一个HTTP请求加JSON解析,用Go写起来特别顺手,标准库就搞定了,连第三方依赖都不用加,你下次跑完马拉松,也可以试试自己写一个——边等成绩边写代码,跑完刚好工具跑通。

本文来自作者[kyadmin]投稿,不代表678体育 - 全网热门体育赛事高清直播平台立场,如若转载,请注明出处:http://66weibo.cn/ty/758.html

(10)

文章推荐

发表回复

本站作者才能评论

评论列表(4条)

  • kyadmin
    kyadmin 2026-07-02

    我是678体育 - 全网热门体育赛事高清直播平台的签约作者“kyadmin”!

  • kyadmin
    kyadmin 2026-07-02

    希望本篇文章《黄河口马拉松成绩查询,用Golang写个查询器,其实没那么难》能对你有所帮助!

  • kyadmin
    kyadmin 2026-07-02

    本站[678体育 - 全网热门体育赛事高清直播平台]内容主要涵盖:678体育,678体育官网,678赛事直播

  • kyadmin
    kyadmin 2026-07-02

    本文概览:为啥我突然想写这个?前几天跑完黄河口马拉松,朋友圈都在晒成绩,我也想去官网查,结果那个页面加载慢得要命,想着自己好歹是个写Go的,干...

    联系我们

    工作时间:周一至周五,9:30-18:30,节假日休息

    关注我们