Skill: zhangbin2025/weiqi-yunbisai (version 1.2.0)

--- name: 云比赛网围棋数据查询 description: weiqi-yunbisai 云比赛网围棋比赛数据查询 - 支持比赛列表、分组信息、对阵数据、排名计算。当用户需要"查比赛"、"云比赛网"、"围棋比赛"时使用此技能。 tags: ["围棋", "weiqi", "go", "比赛", "云比赛网", "排名", "对阵"] --- # 云比赛网完整数据查询 > **🔒 安全说明**: 本技能通过云比赛网公开 API 查询围棋比赛公开数据。所有请求仅读取公开的赛事信息、分组数据和比赛结果，不涉及任何敏感信息或未经授权的访问。代码开源可审计。 > > **v1.2.0 更新**: 新增对手分逆减破同分规则，支持两种排名模式（默认/简化）。 > > **v1.1.1 安全更新**: 已修复潜在 HTML 注入漏洞，所有从 API 获取的数据（选手名、比赛标题等）在生成 HTML 报告前均进行转义处理。 ## 功能描述 完整的云比赛网(yunbisai.com)围棋比赛数据查询技能包，支持从比赛发现到个人对局记录的全流程查询。 ## 依赖安装 ```bash pip3 install requests ``` --- ## 🚀 快速查询工具（带性能跟踪） **脚本**: `scripts/query.py` ### 功能特性 - ✅ 比赛列表查询（支持多页自动抓取） - ✅ 分组信息查询 - ✅ 分组选手查询 - ✅ 完整对阵数据获取 - ✅ 自动排名计算（积分/对手分/累进分） - ✅ **详细性能计时** - 每个步骤耗时统计 ### 使用方法 ```bash # 查询广东省最近1个月的比赛 python3 scripts/query.py # 查询浙江省最近3个月的比赛 python3 scripts/query.py --area "浙江省" --month 3 # 关键词搜索（在所有比赛中搜索含"秦山"的比赛） python3 scripts/query.py --area "浙江省" --month 6 --keyword "秦山" # 查询指定比赛的分组 python3 scripts/query.py --event-id 12345 # 查询分组并计算完整排名 python3 scripts/query.py --event-id 12345 --group-id 67890 --ranking # 使用简化排名模式（跳过累进分） python3 scripts/query.py --event-id 12345 --group-id 67890 --ranking --ranking-mode simple # 查询指定轮次对阵表 python3 scripts/query.py --event-id 12345 --group-id 67890 --matchups 1 # JSON 输出（含性能数据） python3 scripts/query.py --event-id 12345 --group-id 67890 --ranking --json # 静默模式（减少日志输出） python3 scripts/query.py --group-id 67890 --ranking --quiet ``` ### 区域搜索说明 **重要**：搜索特定省份比赛时，使用 `--area` 参数： ```bash # ✅ 正确用法 - 使用完整省份名称 python3 scripts/query.py --area "浙江省" --month 3 python3 scripts/query.py --area "广东省" --month 1 # ✅ 配合关键词快速定位比赛 python3 scripts/query.py --area "浙江省" --keyword "秦山核电" ``` **区域代码参考**： - `广东省`、`浙江省`、`江苏省`、`山东省` ... ### 输出格式规则 脚本根据数据量自动选择输出格式： - **≤ 10 行**：单行 Markdown 格式（便于阅读和复制） - **> 10 行**：自动导出为 HTML 文件（手机端优化），同时显示前10条预览 **单行格式示例（≤10行）：** ``` 📋 找到 10 场比赛 • [12345] **2026年某省第X届"XX杯"业余围棋段级位赛** | 城市: 某市 | 日期: 2026-03-29 • [12346] **2026年某市围棋友谊赛** | 城市: 某市 | 日期: 2026-03-21 ... 📋 排名列表 1. **选手A** | 积分: 12 | 对手分: 48 | 累进分: 42 | 6胜0负 2. **选手B** | 积分: 10 | 对手分: 44 | 累进分: 40 | 5胜1负 ... ``` **HTML 导出示例（>10行）：** ``` 📊 排名数据已导出到 HTML 文件: /tmp/ranking_1234567890.html 共 67 条记录 📋 前10名预览: 1. **选手A** | 积分: 16 | 对手分: 88 | 累进分: 72 | 8胜0负 2. **选手B** | 积分: 14 | 对手分: 96 | 累进分: 70 | 7胜1负 ... ... 还有 57 名选手 ``` **HTML 文件特点（手机端优化）：** - 📱 **完美适配手机**：响应式设计，适配各种屏幕尺寸 - 🎨 **卡片式布局**：列表项采用卡片设计，易于滑动浏览 - 🏷️ **视觉层次分明**：排名、姓名、数据清晰分离 - 🥇 **前3名特殊标识**：前三名红色高亮显示 - 🎖️ **前8名获奖标识**：第4-8名橙色标识，并带"获奖"标签 - 📌 **固定头部**：标题栏随页面滚动固定顶部 - 👆 **点击反馈**：点击时有视觉反馈效果 - 🚫 **禁止缩放**：优化移动端浏览体验 ### 📤 文件发送方式 当通过 QQ 等即时通讯工具发送时，使用 `<qqmedia>` 标签发送 HTML 文件： ``` 对阵表已生成： <qqmedia>/tmp/matchups_xxx.html</qqmedia> ``` **注意**： - 必须使用 `<qqmedia>绝对路径</qqmedia>` 格式 - 文件大小需小于 10MB - 系统会根据扩展名自动识别为文件类型 ### 性能报告示例 ``` ================================================== ⏱️ 性能计时报告 ================================================== 获取所有轮次对阵 : 0.555s ( 99.9%) 获取第1轮对阵 : 0.220s ( 39.6%) 获取第2轮对阵 : 0.064s ( 11.6%) 获取第3轮对阵 : 0.065s ( 11.6%) ... 计算排名 : 0.000s ( 0.0%) -------------------------------------------------- 步骤累计 : 1.109s 总耗时 : 0.555s ================================================== ``` --- ## 技能链条 ## 技能链条 ### 1️⃣ 获取比赛列表 **API**: `https://data-center.yunbisai.com/api/lswl-events` **用途**: 获取某个区域/时间段的所有围棋比赛 **参数**: - `areaNum`: 区域（如广东省） - `month`: 最近多少个月 - `eventType`: 2（围棋） - `page`: 页码 - `PageSize`: 每页数量 **示例**: ```bash curl -s "https://data-center.yunbisai.com/api/lswl-events?page=1&eventType=2&month=1&areaNum=%E6%9F%90%E7%9C%81&PageSize=50" ``` **返回**: event_id, title, city_name, play_num 等 --- ### 2️⃣ 获取比赛分组 **API**: `https://open.yunbisai.com/api/event/feel/list` **用途**: 获取指定比赛的所有分组 **参数**: - `event_id`: 比赛ID - `page`: 1 - `pagesize`: 500 **示例**: ```bash curl -s -H "Referer: https://www.yunbisai.com/" \ "https://open.yunbisai.com/api/event/feel/list?event_id=12345&page=1&pagesize=500" ``` **返回**: group_id, groupname, 选手列表, 排名, 积分 **关键字段**: - `group_id`: 分组唯一标识 - `groupname`: 组别名称（如"5段及以上组"） - `participantname`: 选手姓名 - `rank_num`: 排名 - `integral`: 积分 - `vicsum`/`faisum`: 胜/负场数 --- ### 3️⃣ 获取分组选手 **API**: `https://open.yunbisai.com/api/event/feel/list` **用途**: 获取指定分组的详细选手信息 **参数**: - `event_id`: 比赛ID - `group_id`: 分组ID - `page`: 1 - `pagesize`: 200 **示例**: ```bash curl -s -H "Referer: https://www.yunbisai.com/" \ "https://open.yunbisai.com/api/event/feel/list?event_id=12345&group_id=67890&page=1&pagesize=200" ``` --- ### 4️⃣ 获取对局详情 **API**: `https://api.yunbisai.com//request/Group/Againstplan` **用途**: 获取某组某轮的详细对阵表 **参数**: - `groupid`: 分组ID - `bout`: 轮次（1, 2, 3...） **示例**: ```bash curl -s -A "Mozilla/5.0" \ "https://api.yunbisai.com//request/Group/Againstplan?groupid=67890&bout=1" ``` **返回关键字段**: - `total_bout`: 总轮数 - `rows`: 对局列表 - `p1`, `p2`: 选手姓名 - `p1_score`, `p2_score`: 得分（2=胜, 1=和, 0=负） - `seatnum`: 台号 - `p1_teamname`, `p2_teamname`: 所属团队 --- ### 5️⃣ 统计选手成绩 **流程**: 1. 获取第1轮得到 `total_bout` 2. 遍历所有轮次（1 到 total_bout） 3. 累加每个选手的得分 4. 按总分排序 **计分规则**: - 胜: 2分 - 和: 1分 - 负: 0分 **重要**: 使用 `p1_score` / `p2_score` 字段（0=负, 1=和, 2=胜），**不要**使用 `p1_result` / `p2_result` --- ### 5️⃣ 排名计算规则 #### 1. 个人积分 - 胜：2分 - 和：1分 - 负：0分 #### 2. 对手分 所有已赛对手的个人积分之和 #### 3. 累进分 每轮结束后的累计积分之和 示例：4胜1负选手的累进分 - 第1轮后：2分 - 第2轮后：4分 - 第3轮后：6分 - 第4轮后：8分 - 第5轮后：8分（负） - 累进分 = 2+4+6+8+8 = **28分** #### 4. 排名优先级 **默认模式** (`--ranking-mode default`): 1. **个人积分**（高者优先） 2. **对手分**（高者优先） 3. **累进分**（高者优先） 4. **对手分逆减**（高者优先） **简化模式** (`--ranking-mode simple`): 1. **个人积分**（高者优先） 2. **对手分**（高者优先） 3. **对手分逆减**（高者优先，跳过累进分） #### 5. 对手分逆减规则 当积分、对手分（和累进分）都相同时，使用对手分逆减破同分： **计算方法**： 1. 从末轮开始，逐轮减去该轮对手的积分 2. 每递减一轮后比较剩余值 3. 当某一轮能区分排名时，停止并显示该轮结果 4. 显示格式：`n-剩余值`（如 `2-12` 表示递减2轮后剩余12分） **示例**： ``` 选手A: 总对手分=18，各轮对手分=[4,8,2,4] 递减1轮: 18-4=14 递减2轮: 14-2=12 ← 显示 "2-12" 选手B: 总对手分=18，各轮对手分=[4,6,4,4] 递减1轮: 18-4=14 递减2轮: 14-4=10 ← 显示 "2-10" 结果：A排名靠前（12>10） ``` #### 5. 轮空处理 - 轮空选手的对手是 `None` / `null` - 轮空获胜也得2分 - 轮空对手的积分（0分）不计入对手分 #### 6. 未完成轮次的处理 ⚠️ **重要**：计算排名时，必须检查每一轮是否已经完成。 **判断方法**： ```python # 如果一轮中所有对局的 p1_score 和 p2_score 都是 0.0 # 说明该轮对阵表已出，但比赛尚未完成 is_round_completed = any( m.get('p1_score') not in [None, 0.0] or m.get('p2_score') not in [None, 0.0] for m in round_data ) ``` **处理规则**： - ✅ **已完成的轮次**：正常计入排名计算 - ❌ **未完成的轮次**：**不得计入**排名计算，即使对阵表已发布 **错误示例**： > 某比赛第2轮，所有对局 p1_score=0.0, p2_score=0.0，表示比赛还在进行中。若此时计入排名，会导致所有选手都是0分，排名计算错误。 **正确做法**： > 只计算已完成的轮次（如第1轮），未完成的轮次等比赛结束后再更新。 --- ### 6️⃣ 查询特定选手 **流程**: 1. 通过比赛列表找到 `event_id` 2. 获取比赛所有选手，筛选出目标选手 3. 得到 `group_id` 和基本信息 4. 遍历该组所有轮次对局 5. 筛选出目标选手的每轮对局 --- ## 完整使用示例 ### 示例1：查找某选手在指定比赛的成绩 ```python import requests # 配置 player_name = "张三" event_id = 12345 # 示例比赛ID # 步骤1：获取比赛所有选手，找到目标选手的分组 response = requests.get( f"https://open.yunbisai.com/api/event/feel/list?event_id={event_id}&page=1&pagesize=500", headers={"Referer": "https://www.yunbisai.com/"} ) for row in response.json()['datArr']['rows']: if row['participantname'] == player_name: group_id = row['group_id'] print(f"找到！组别: {row['groupname']}, 排名: {row['rank_num']}") break # 步骤2：获取该组所有轮次对局 total_bout = 8 # 从API获取 base_url = "https://api.yunbisai.com//request/Group/Againstplan" for bout in range(1, total_bout + 1): response = requests.get(f"{base_url}?groupid={group_id}&bout={bout}") # 处理对局数据... ``` --- ## 已掌握的实战案例 ### 个人成绩查询示例 | 选手 | 比赛 | 组别 | 成绩 | 排名 | |------|------|------|------|------| | 选手A | 示例杯 | 儿童组 (12345) | 14分 (7胜2负) | 第7名 | | 选手B | 示例杯 | 少年组 (12346) | 14分 (7胜3负) | - | | 选手C | 示例赛 | 5段组 (12347) | 14分 (7胜1负) | 第10名 | ### 分组排行榜案例 #### 案例1: 示例比赛 - 4段组 - **event_id**: 12345 - **group_id**: 67890 - **参赛人数**: 15人 - **比赛轮次**: 5轮 | 排名 | 姓名 | 积分 | 对手分 | 累进分 | 战绩 | |:---:|:---:|:---:|:---:|:---:|:---:| | 🥇 | 选手A | 10 | 28 | 30 | 5胜0负 | | 🥈 | 选手B | 8 | 30 | 20 | 4胜1负 | | 🥉 | 选手C | 8 | 20 | 24 | 4胜1负 | | 4 | 选手D | 6 | 36 | 24 | 3胜2负 | | 5 | 选手E | 6 | 22 | 16 | 3胜2负 | **排名分析**: - 第2名 vs 第3名：同积8分，第2名对手分更高(30>20) - 第6名：仅2胜，但对手分高达36，说明对手实力强 #### 案例2: 示例比赛 - 3段组 - **event_id**: 12345 - **group_id**: 67891 - **参赛人数**: 24人 - **比赛轮次**: 5轮 | 排名 | 姓名 | 积分 | 对手分 | 累进分 | 战绩 | |:---:|:---:|:---:|:---:|:---:|:---:| | 🥇 | 选手F | 8 | 34 | 26 | 4胜1负 | | 🥈 | 选手G | 8 | 30 | 28 | 4胜1负 | | 🥉 | 选手H | 8 | 30 | 22 | 4胜1负 | **排名分析**: - 前5名同积8分，按对手分排名 - 第2名 vs 第3名：对手分相同(30)，比较累进分(28>22) --- ## 触发指令 ``` "查一下XXX在YYY比赛的成绩" "获取ZZZ比赛的分组信息" "列出AAA组的所有对局" "统计BBB选手每轮的胜负" ``` --- ## 排名计算完整代码 ```python import json # 读取各轮对阵数据 rounds_data = [] for bout in range(1, total_bout + 1): with open(f'group{bout}.json', 'r') as f: data = json.load(f) rounds_data.append(data['datArr']['rows']) # 初始化选手数据 players = {} # 第一轮：初始化所有选手（跳过None轮空） for match in rounds_data[0]: for key, name_key, team_key in [('p1id', 'p1', 'p1_teamname'), ('p2id', 'p2', 'p2_teamname')]: pid = match.get(key) name = match.get(name_key) team = match.get(team_key) or '' if pid and name and pid not in players: players[pid] = { 'name': name, 'team': team, 'wins': 0, 'losses': 0, 'draws': 0, 'score': 0, 'opponents': [], 'progressive': [] # 每轮累计积分 } # 逐轮解析 - 使用p1_score和p2_score计算积分 for round_idx, round_data in enumerate(rounds_data, 1): for match in round_data: p1_id = match.get('p1id') p2_id = match.get('p2id') p1_score = float(match.get('p1_score') or 0) # 0=负, 1=和, 2=胜 p2_score = float(match.get('p2_score') or 0) # 处理p1 if p1_id and p1_id in players: if p2_id and match.get('p2') and p2_id in players: players[p1_id]['opponents'].append(p2_id) if p1_score == 2.0: players[p1_id]['wins'] += 1 elif p1_score == 0.0: players[p1_id]['losses'] += 1 else: players[p1_id]['draws'] += 1 players[p1_id]['score'] += p1_score # 处理p2 if p2_id and p2_id in players: if p1_id and match.get('p1') and p1_id in players: players[p2_id]['opponents'].append(p1_id) if p2_score == 2.0: players[p2_id]['wins'] += 1 elif p2_score == 0.0: players[p2_id]['losses'] += 1 else: players[p2_id]['draws'] += 1 players[p2_id]['score'] += p2_score # 记录每轮后的累计积分（累进分） for pid in [p1_id, p2_id]: if pid and pid in players: players[pid]['progressive'].append(players[pid]['score']) # 计算对手分和累进分 for pid, p in players.items(): p['opponent_score'] = sum(players[oid]['score'] for oid in p['opponents'] if oid in players) p['progressive_score'] = sum(p['progressive']) # 排序：个人积分 > 对手分 > 累进分 sorted_players = sorted( players.items(), key=lambda x: (x[1]['score'], x[1]['opponent_score'], x[1]['progressive_score']), reverse=True ) # 输出排行榜 for i, (pid, p) in enumerate(sorted_players, 1): print(f"{i}. {p['name']} | 积分:{int(p['score'])} | 对手分:{int(p['opponent_score'])} | 累进分:{int(p['progressive_score'])}") ``` **关键要点：** 1. 使用 `p1_score` / `p2_score`（0/1/2）计算积分，**不要**用 `p1_result` / `p2_result` 2. 只添加有名字的选手（`name is not None`），跳过轮空 3. 轮空对手的积分（0分）不计入对手分 4. 每轮结束后记录累计积分（累进分） 5. 排序优先级：**个人积分 > 对手分 > 累进分** --- ## 输出规范 查询选手对局情况时，必须同时提供： 1. **对局详情** - 每轮对手、胜负、得分 2. **对手分** - 所有对手的总积分之和（通过遍历所有轮次累计） 3. **累进分** - 每轮累计得分的累加（第1轮累计 + 第2轮累计 + ...） 示例格式： ``` 【对局记录】 轮次 | 对手 | 结果 | 得分 ... 【对手分统计】 对手总分: XXX 分 【累进分统计】 累进分合计: XXX 分 ``` --- ## 附加API参考 ### 获取比赛列表（替代方案） **API**: `https://data-center.yunbisai.com/api/lswl-events` **参数**: - `areaNum`: 区域（URL编码，如广东省=%E5%B9%BF%E4%B8%9C%E7%9C%81） - `month`: 最近多少个月（1, 3, 6, 12） - `eventType`: 2（围棋） - `PageSize`: 每页数量 **示例**: ```bash curl -s "https://data-center.yunbisai.com/api/lswl-events?page=1&areaNum=%E5%B9%BF%E4%B8%9C%E7%9C%81&month=1&eventType=2&PageSize=36" ``` **返回字段**: - `event_id`: 比赛ID - `title`: 比赛名称 - `city_name`: 城市 - `cname`: 主办单位 - `min_time`/`max_time`: 比赛时间 - `play_num`: 参赛人数 - `contact`/`linkMan`: 联系人及电话 --- ## 触发指令汇总 ``` # 比赛查询 "查一下最近X个月[地区]的围棋比赛" "列出[地区]最近的围棋赛事" # 分组查询 "查询比赛ID为XXX的分组信息" "获取比赛XXX的所有组别" "列出比赛XXX的选手名单" # 排名计算 "查一下[event_id]比赛[group_name]组的排名" "计算[event_id]比赛[group_name]组的排行榜" # 个人成绩 "查一下XXX在YYY比赛的成绩" "统计BBB选手每轮的胜负" ``` --- ## 数据来源 - **平台**: 云比赛网 (yunbisai.com) - **数据类型**: 围棋比赛、分组信息、对阵表、选手成绩


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (MEDIUM)