news 2026/9/18 20:41:11

kleague-results 使用指南:基于官方 K League JSON 端点的 Node.js 赛果与积分榜客户端

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
kleague-results 使用指南:基于官方 K League JSON 端点的 Node.js 赛果与积分榜客户端

kleague-results 使用指南:基于官方 K League JSON 端点的 Node.js 赛果与积分榜客户端

【免费下载链接】k-skill한국인을 위한 스킬 모음집 - 에이전트를 한국인으로项目地址: https://gitcode.com/GitHub_Trending/ks/k-skill

本指南围绕仓库中的 kleague-results 包 展开,它是一个封装韩国职业足球联赛(K리그)官方 JSON 接口的可复用 Node.js 客户端,可同时按日期查询比赛结果与当前积分榜。读完本文,你将掌握该包的安装方式、三个核心 API(getMatchResults/getStandings/getKLeagueSummary)的参数与返回值结构,并能结合 源码实现 与 测试用例 理解其日期过滤、球队别名匹配、状态归一化等底层原理。

为什么用官方 JSON 端点而不是 HTML 爬虫

K리그 官方站点的比赛数据是动态页面,传统做法是抓取 HTML 后解析 DOM。该包选择直接请求官方 JSON 接口,维护成本显著低于 HTML 爬虫——只要官方接口的响应结构不变,客户端就不需要频繁适配页面改版。包内硬编码了两个官方数据表面:

数据内容端点请求方式
赛程 / 比赛结果https://www.kleague.com/getScheduleList.doPOST,按月请求
球队积分榜https://www.kleague.com/record/teamRank.doPOST,携带 query 参数

这两个 URL 在 src/index.js 中定义为常量,测试用例也通过构造相同的端点来模拟请求(见 test/index.test.js)。

安装与运行环境

包要求Node.js 18+(在 package.json 的engines字段中声明),因为实现依赖原生global.fetch。安装方式:

npm install kleague-results

如果你要在 Agent / CLI 场景中直接使用,可以全局安装:

npm install -g kleague-results

该包是 k-skill 仓库中 kleague-results 技能 的数据层,技能文档建议在全局 Node 包缺失时先安装kleague-results,而不是用 HTML 抓取绕过(见 instruction.md)。

快速上手

下面是最小可用示例,同时演示了三个 API 的调用方式(摘自包 README):

const { getKLeagueSummary, getMatchResults, getStandings } = require("kleague-results"); (async () => { const results = await getMatchResults("2026-03-22", { leagueId: "K리그1", team: "FC서울", }); const standings = await getStandings({ leagueId: 1, year: 2026, }); const summary = await getKLeagueSummary("2026-03-22", { leagueId: "K리그1", team: "FC서울", includeStandings: true, }); console.log(results.matches[0]); console.log(standings.rows[0]); console.log(summary); })();

从 package.json 可以看出,该包的main入口是src/index.js,发布时仅包含src目录和README.md,也就是说你安装后引入的正是下面将要分析的源码。

API 详解

包对外暴露三个主要异步函数,另有两个底层请求函数fetchScheduleMonth/fetchStandings供高级复用(见 src/index.js 的导出列表)。

getMatchResults(date, options)

按日期查询某一联赛的比赛结果,可选按球队过滤。

  • dateYYYY-MM-DD字符串或Date对象
  • options.leagueId12K리그1K리그2(也接受K1KLEAGUE1K2KLEAGUE2等别名)
  • options.team:球队简称 / 全名 / 球队代码别名,例如서울FC서울K09

返回对象包含queryDateleagueIdfilteredTeam(指定球队时的归一化结果)、clubs(参赛球队目录)和matches(规范化后的比赛数组)。

getStandings(options)

查询当前积分榜。

  • options.leagueId12
  • options.year:赛季年份,默认取韩国时区(Asia/Seoul)的当前年份。该默认值由源码中的getCurrentKoreaYear()实现,使用Intl.DateTimeFormat并指定timeZone: "Asia/Seoul"(见 src/index.js)

返回对象包含leagueIdyearisSplitRanknoticerows(积分榜行数组)。

getKLeagueSummary(date, options)

一次调用同时返回「某日比赛结果 + 当前积分榜」,是 Agent 场景下最常用的组合接口。optionsgetMatchResults相同,额外支持includeStandings(默认true,源码中判断条件为options.includeStandings !== false,见 src/index.js)。

其组合逻辑是:先取比赛结果,再以查询日期中的年份为赛季年份调用积分榜(matches.queryDate.slice(0, 4)),并把比赛中出现的球队目录传给积分榜解析,从而保证两边球队名称一致(见 src/index.js)。

参数归一化:别名、日期与时区

leagueId 的别名解析

normalizeLeagueId维护了一张别名映射表(见 src/parse.js):

规范化结果接受的别名
1(K리그1)1K1KLEAGUE1K리그1
2(K리그2)2K2KLEAGUE2K리그2

解析前会先做normalizeToken处理:NFKC 归一化、转大写、剔除除字母数字与韩文外的字符。因此"k league 2"也能被解析为2(测试用例 index.test.js 验证了这一点)。传入K리그3等无法解析的值会抛出leagueId must resolve to K League 1 or 2错误;空值则默认回退到1

date 的解析与校验

normalizeDateInput支持YYYY-MM-DDYYYY.MM.DD两种字符串格式,也接受Date对象;Date对象会按Asia/Seoul时区格式化为日期部分,避免时区偏移导致日期串位。字符串格式会经过严格的日历校验(含闰年判断),2026-13-40这类不存在的日期在发起任何网络请求之前就会被拒绝——测试 index.test.js 专门验证了这一点(断言fetchCalledfalse)。

team 的别名匹配

buildClubDirectory从响应中的clubList构建球队目录,为每支球队收集teamId(如K09)、简称(서울)、全名(FC서울)等所有字段作为别名 token。resolveTeamQuery会用同样的 token 规范化方式匹配用户输入,因此서울FC서울K09都能命中同一支球队。注意서울这类短名在 K리그2 中可能对应서울 이랜드,技能文档明确提示了这种歧义(见 instruction.md 的 Failure modes 一节)。

数据规范化:原始 JSON 如何变成结构化对象

官方接口返回的是面向展示的原始 JSON(可在 fixtures 中查看真实响应样本),包在src/parse.js中将其转换为便于程序消费的结构。

比赛状态映射

normalizeMatchStatus将官方状态码映射为统一语义(见 src/parse.js):

状态码statelabel
FEfinished종료(已结束)
NSscheduled예정(未开始)
LIVE/INlive진행 중(进行中)
HThalftime하프타임(中场休息)
PPpostponed연기(延期)
CANcancelled취소(取消)

比赛对象字段

每场比赛被规范化为如下结构(见normalizeScheduleItem,src/parse.js):

  • leagueIdcompetitionName(如하나은행 K리그1 2026)、roundgameId
  • date(转为2026-03-22格式)、dateLabelkickOff
  • status:上述状态对象
  • homeTeam/awayTeam{ code, name, fullName, homepage, leagueId }
  • score{ home, away },未开赛时返回null
  • winner:仅在已结束时返回home/away/draw,由determineWinner计算
  • venue{ shortName, name },如서울 월드컵 경기장
  • audiencebroadcastChannels(用//|拆分的转播频道数组)
  • matchCenterUrl:由gameIdmeetSeq拼接的官方比赛中心链接

测试 index.test.js 用 2026-03-22 的 fixture 验证了完整映射:FC서울 主场 5:0 胜 광주、第 5 轮、状态FE/종료

积分榜行对象

normalizeStandingsResponse将官方teamRank数组规范化为(见 src/parse.js):

  • rankteam(含 code / name / fullName)
  • points(积分)、played(场次)、win/draw/loss(胜/平/负)
  • goalsFor/goalsAgainst/goalDifference(进/失/净胜球)
  • form:最近 6 场走势数组(game01game06,值为//
  • homepagestadium

此外会按rank升序、同分按积分降序、再按韩文队名排序,并用teamId去重。测试断言 2026 赛季 K리그1 有 12 行,서울 以 12 分居首、4 战全胜(见 index.test.js)。

底层请求细节

src/index.js中的requestJson统一处理 HTTP 调用:默认请求头包含accept-language: ko-KR以锁定韩文数据、user-agent: k-skill/kleague-results,并透传signal(AbortSignal)与可替换的fetchImpl(便于测试注入 mock)。

两个端点的请求方式不同,值得注意:

  • 赛程接口:POST,body 为{ year, month, leagueId },其中month会补零成两位(如"03")。由于该接口按月返回数据,包必须在客户端再次按请求日期精确过滤——测试用例专门断言了请求体包含"month":"03"(见 index.test.js)。
  • 积分榜接口:POST,query 参数为leagueIdyearstadium=allrecordType=rankstadium=all表示当前为全主场口径的积分榜,包 README 的 Notes 部分对此有明确说明。

getMatchResults内部通过fetchScheduleMonth拿整月数据,再用normalizeScheduleResponse过滤出指定日期;getKLeagueSummary则在其上叠加积分榜调用,测试验证了组合调用时getScheduleList.do会被请求两次(一次在getMatchResults,一次在getKLeagueSummary内部,见 index.test.js)。

在 Agent / CLI 场景中的实际用法

该包是 k-skill 生态中 K리그 技能的数据层。技能工作流(见 instruction.md 与 docs/features/kleague-results.md)建议:

  1. 检查npm root -g下是否存在kleague-results,缺失则npm install -g kleague-results不要用 HTML 抓取绕过
  2. 调用getKLeagueSummary一次拿到比赛与排名;
  3. 将原始 JSON 整理为人类可读结果:主客队、开赛时间 / 是否已结束、比分、当前排名,若指定球队则只保留该队比赛;
  4. 保持回答紧凑:scoreboard 请求先给逐场一行摘要;单队请求先给该队比赛与当前排名。

在非包安装环境下,可用下面这种方式直接从全局 npm 目录加载模块(来自 docs/features/kleague-results.md 的示例):

GLOBAL_NPM_ROOT="$(npm root -g)" node --input-type=module - <<'JS' import path from "node:path"; import { pathToFileURL } from "node:url"; const entry = pathToFileURL( path.join(process.env.GLOBAL_NPM_ROOT, "kleague-results", "src", "index.js"), ).href; const { getKLeagueSummary } = await import(entry); const summary = await getKLeagueSummary("2026-03-22", { leagueId: "K리그1", team: "FC서울", includeStandings: true, }); console.log(JSON.stringify(summary, null, 2)); JS

边界情况与失败模式

综合包 README 的 Notes 与技能文档的 Failure modes,使用中需要注意:

  • getScheduleList.do月粒度接口,必须依赖库内按日过滤,不要假设返回即当日数据;
  • 查询日期在比赛开始之前时,返回的是예정(scheduled)或진행 중(live)状态,scorewinnernull
  • 서울这类短名跨联赛存在歧义,K리그2 场景下应确认是否指서울 이랜드
  • 官方接口若改变getScheduleList.do/teamRank.do的响应结构,则需要更新包内的解析逻辑(src/parse.js 是主要维护点);
  • 日期参数在请求前即被严格校验,非法日历日期不会触发网络请求。

本地验证方式

该包自带基于node:test的测试,覆盖了联赛别名解析、日期过滤、球队别名匹配、状态映射、积分榜结构以及「mock fetch 下的三 API 组合调用」等场景(见 packages/kleague-results/test/index.test.js)。测试依赖两份真实响应快照:schedule-kleague1-2026-03.json(2026 年 3 月 K리그1 赛程与俱乐部列表)和 standings-kleague1-2026.json(2026 赛季 K리그1 积分榜)。在包目录下执行即可运行:

npm test

代码风格检查则通过node --check对三个 JS 文件做语法校验(npm run lint,见 package.json)。

总结

kleague-results 是一个「官方 JSON 端点 + 客户端归一化」的典型封装:对外提供三个语义清晰的异步 API,对内完成 leagueId 别名归一化、韩国时区日期解析、球队别名匹配、比赛/积分榜结构标准化。它规避了 HTML 爬虫的脆弱性,并把「月粒度数据按日过滤」「stadium=all积分榜」等官方接口特性封装成对调用方透明的能力。若你要在 Node.js 应用中集成 K리그 数据,或为 Agent 构建韩国体育信息查询能力,可直接参考本包 README、源码 与 测试 作为起点。

【免费下载链接】k-skill한국인을 위한 스킬 모음집 - 에이전트를 한국인으로项目地址: https://gitcode.com/GitHub_Trending/ks/k-skill

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/18 20:40:07

课程论文交付前清单:用书霸AI写作

www.shubaai.com课程论文最容易出现的问题&#xff0c;不一定是“不会写”&#xff0c;而是写作过程中缺少一套稳定的检查流程。题目范围过大、文献与观点脱节、格式前后不统一&#xff0c;往往会让一篇本来有想法的论文失去完整性。下面这份清单&#xff0c;可以作为课程论文写…

作者头像 李华
网站建设 2026/9/18 20:39:51

Altium Designer 18网络颜色功能全解析:从设置到应用,避免PCB设计返工

1. 网络颜色不是花架子&#xff1a;一次电源返工让我重新认识它在开始讲具体操作之前&#xff0c;我想先聊一段实际经历。上个季度做一块四层电源板&#xff0c;PCB Layout完成得很快&#xff0c;结果样机回来后调试&#xff0c;发现3.3V网络和GND之间阻抗只有几十欧&#xff0…

作者头像 李华
网站建设 2026/9/18 20:39:05

ISO14001:2015中文版PDF条款结构化与合规检索

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/18 20:37:38

仓库标准怎么读,TaoToken 让 Agent 先核对 public-apis 文档

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/18 20:36:36

AI写真保姆级教程:从扩散模型到数字分身,一键生成大片

这两天我的朋友圈和几个短视频平台都被同一件事刷屏了——AI写真。不只是年轻人玩&#xff0c;连我那几个十几年没拍过正式照片的长辈&#xff0c;都上传了二三十张自拍&#xff0c;生成了一组看不出年龄的职业照和古风写真。如果你还没用过这类免费的AI写真神器&#xff0c;那…

作者头像 李华