Note2026-10-06 更新:本文最初写于开服时,而目前官方 API 返回的数据结构、相关数据的获取和处理都经过了较大变化。现补上赠礼机制、重构池等信息。今天《明日方舟:终末地》公测了。体验了一段时间之后,想着将抽卡数据导入抽卡分析应用中。但是可能是游戏刚开服的缘故,找了一轮都没能找到导出抽卡数据的工具,最终只能自己动手实现这个功能。下面分享主要思路,如果你需要实现这个功能希望对你有所帮助。URL 里都有什么首先,和其他游戏一样,我们可以通过抓包软件抓取或者一些更方便的方法1获取到这样的抽卡记录链接:TEXT複製https://ef-webview.hypergryph.com/api/record/char?lang=zh-cn&seq_id={seqId}&pool_type={poolType}&token={token}&server_id={serverId}抽卡记录链接角色池针对角色池,我们主要关注 pool_type 和 seq_id 这两个参数:pool_type 是卡池枚举值,可以通过下面 API 获取抽卡记录页面提供的角色池:TEXT複製https://ef-webview.hypergryph.com/api/record/char/meta?lang=zh-cn&token={token}&server_id={serverId}返回数据:JSON{ "code": 0, "data": { "tabs": [{ "key": "special", "label": "", "poolType": "E_CharacterGachaPoolType_Special" }, { "key": "rerun", "label": "", "poolType": "E_CharacterGachaPoolType_Rerun" }, { "key": "normal", "label": "", "poolType": "E_CharacterGachaPoolType_Standard" } ], "beginnerPullCount": 40 }, "msg": "" }展開 · 23 行複製目前仅能取如下卡池之一:启程寻访(新手池):E_CharacterGachaPoolType_Beginner基础寻访(常驻池):E_CharacterGachaPoolType_Standard特许寻访(限定池):E_CharacterGachaPoolType_Special重构寻访(复刻池):E_CharacterGachaPoolType_Rerun特殊寻访(辉光庆典):E_CharacterGachaPoolType_Joint而与原神,鸣潮等游戏不同,终末地的抽卡记录链接通常带有 seq_id 参数。JSON// seq_id=26&pool_type=E_CharacterGachaPoolType_Standard { "code": 0, "data": { "list": [ //... { "poolId": "standard", "poolName": "基础寻访", "charId": "chr_0019_karin", "charName": "秋栗", "rarity": 4, "isFree": false, "isNew": false, "gachaTs": "1769073164712", "seqId": "21" } ], "hasMore": false }, "msg": "" } // pool_type=E_CharacterGachaPoolType_Beginner { "code": 0, "data": { "list": [ { "poolId": "beginner", "poolName": "启程寻访", "charId": "chr_0022_bounda", "charName": "萤石", "rarity": 4, "isFree": false, "isNew": false, "gachaTs": "1769072324787", "seqId": "20" //该卡池最新的抽卡记录 }, // ... ], "hasMore": true }, "msg": "" }展開 · 45 行複製通过观察上面两个不同卡池的记录,我们可以发现 seq_id 参数的一些特征:seq_id (seqId) 是一个 账号级的、跨子卡池的、不同类型卡池互相独立的 递增序号,所有角色子卡池的抽卡记录共享同一条 seq_id (seqId) 序列,而武器子卡池的抽卡记录共享另一条 seq_id (seqId) 序列。在同一卡池类型(所有角色池或者所有武器池)下,即使我们更换子卡池的类型也不会让 seq_id (seqId) 重新开始计数。seq_id (seqId) 数字越大,时间越晚、数据越新。当请求的链接不带 seq_id 参数的时候会返回该卡池最新的五条记录(即 seqId 最大的五条记录)。根据这些特征我们可以知道:在游戏里的抽卡记录展示页中,我们从第一页开始往后翻(从新记录到旧记录)的过程就是抽卡记录链接 seq_id 参数递减的过程。在链接返回的抽卡记录中,还会带有一个 hasMore 参数。其代表的是当前返回结果的最小 seqId 之下是否还有数据,反映到抽卡页面就是 是否还能翻下一页。此外,终末地的卡池有赠礼机制。当期特许寻访累计达到 60 次,会额外获得 1 本寻访情报书,接口也会添加一条 kind: "gift_intel_book" 的奖励记录。在处理抽卡数据的时候需要对其进行过滤,否则会出现接口返回的记录条数与抽卡次数不一致。武器池与角色池相似,武器池同样可以通过两个 API 获取记录:获取武器池列表先通过下面的链接获取用户存在抽卡记录的武器池列表:TEXT複製https://ef-webview.hypergryph.com/api/record/weapon/pool?lang=zh-cn&token={token}&server_id={serverId}返回的数据结构:JSON複製{ "code": 0, "data": [ { "poolId": "weponbox_1_0_1", "poolName": "熔铸申领" }, { "poolId": "weaponbox_constant_2", "poolName": "星声申领" } // ... ], "msg": "" }这里可以看到武器池分为几种类型:武器限定池:poolId 格式为 weponbox_*(如 weponbox_1_0_1),对应当期 UP 武器武器常驻池:poolId 格式为 weaponbox_constant_*(如 weaponbox_constant_2)武器重构池:poolType === "rerun"Note这里有意思的是,武器限定池的 weapon 前缀拼写为了 wepon获取武器抽卡记录获取具体武器池的抽卡记录链接与角色池抽卡记录链接格式有所不同,武器池的抽卡记录链接将 pool_id 参数代替了 pool_type 参数:TEXT複製https://ef-webview.hypergryph.com/api/record/weapon?lang=zh-cn&seq_id={seqId}&pool_id={poolId}&token={token}&server_id={serverId}其返回的数据结构为:JSON{ "code": 0, "data": { "list": [ { "poolId": "weponbox_1_0_1", "poolName": "熔铸申领", "weaponId": "wpn_funnel_0010", "weaponName": "骑士精神", "weaponType": "E_WeaponType_Wand", "rarity": 6, "isNew": true, "gachaTs": "1769238381938", "seqId": "47" }, // ... ], "hasMore": true }, "msg": "" }展開 · 21 行複製武器记录的字段与角色记录略有不同:weaponId:武器 IDweaponName:武器名称weaponType:武器类型(E_WeaponType_Sword、E_WeaponType_Wand 等)武器池的 seq_id 特性与角色池相同,所有武器子卡池共享同一条 seqId 序列。至此,我们已经基本搞清楚了《明日方舟:终末地》抽卡记录链接的逻辑。主要思路根据上面的介绍,我们能构想出通过一个有效的终末地抽卡记录链接来获取当前可以查询的所有记录的方法:角色池先通过 API 获取账号的有效角色池,使用返回的 poolType 不带 seq_id 获取该子池最新的抽卡记录。后续使用返回数据中最小 seqId 作为游标,遍历该卡池的所有记录,直至后续抽卡数据被服务器清理或着到了该卡池的第一次抽卡 hasMore === false 停止。切换为另一个卡池,继续重复第一步的操作即可。武器池首先调用武器池列表 API 获取用户有数据的武器池。遍历每个武器池,使用 pool_id 参数获取记录。将 poolType === "rerun" 判定为武器重构池;其他卡池根据 poolId 判断卡池类型:包含 constant 的为常驻池,否则为限定池。代码实现TypeScript// 获取角色池记录 async function fetchCharacterRecords(token: string, serverId: string) { const metaUrl = `https://ef-webview.hypergryph.com/api/record/char/meta?lang=zh-cn&token=${encodeURIComponent(token)}&server_id=${encodeURIComponent(serverId)}`; const metaResponse = await fetch(metaUrl); if (!metaResponse.ok) throw new Error("获取角色池元数据失败"); const { code, data: meta } = await metaResponse.json(); if (code !== 0 || !Array.isArray(meta?.tabs)) throw new Error("无效的角色池元数据"); const allRecords = []; for (const pool of meta.tabs) { if (typeof pool?.poolType !== "string" || !pool.poolType || (pool.poolId != null && typeof pool.poolId !== "string")) { throw new Error("无效的角色子池"); } let cursor: number | null = null; let hasMore = true; while (hasMore) { const seqIdParam = cursor !== null ? `&seq_id=${cursor}` : ""; const poolIdParam = pool.poolId ? `&pool_id=${encodeURIComponent(pool.poolId)}` : ""; const url = `https://ef-webview.hypergryph.com/api/record/char?lang=zh-cn${seqIdParam}&pool_type=${encodeURIComponent(pool.poolType)}${poolIdParam}&token=${encodeURIComponent(token)}&server_id=${encodeURIComponent(serverId)}`; const response = await fetch(url); if (!response.ok) throw new Error("获取记录失败"); const { code, data } = await response.json(); if (code !== 0 || !Array.isArray(data?.list) || typeof data.hasMore !== "boolean" || (!data.list.length && data.hasMore)) { throw new Error("官方接口返回错误或无效分页"); } if (data.list.length > 0) { allRecords.push(...data.list); hasMore = data.hasMore; if (hasMore) { const seqIds = data.list.map((item: { seqId: string }) => Number(item.seqId)); if (seqIds.some((id: number) => !Number.isSafeInteger(id) || id <= 0)) { throw new Error("序号超出安全整数范围或格式无效"); } const nextCursor = Math.min(...seqIds); if (cursor !== null && nextCursor >= cursor) throw new Error("分页游标未前进"); cursor = nextCursor; await new Promise(resolve => setTimeout(resolve, 300)); } } else { hasMore = false; } } } return allRecords; } // 获取武器池记录 async function fetchWeaponRecords(token: string, serverId: string) { const allRecords = []; const poolListUrl = `https://ef-webview.hypergryph.com/api/record/weapon/pool?lang=zh-cn&token=${encodeURIComponent(token)}&server_id=${encodeURIComponent(serverId)}`; const poolListResponse = await fetch(poolListUrl); if (!poolListResponse.ok) throw new Error("获取武器池列表失败"); const { code, data: weaponPools } = await poolListResponse.json(); if (code !== 0 || !Array.isArray(weaponPools)) throw new Error("无效的武器池列表"); for (const pool of weaponPools) { if (typeof pool.poolId !== "string" || !pool.poolId) throw new Error("武器池缺少标识"); let cursor: number | null = null; let hasMore = true; while (hasMore) { const seqIdParam = cursor !== null ? `&seq_id=${cursor}` : ""; const url = `https://ef-webview.hypergryph.com/api/record/weapon?lang=zh-cn${seqIdParam}&pool_id=${encodeURIComponent(pool.poolId)}&token=${encodeURIComponent(token)}&server_id=${encodeURIComponent(serverId)}`; const response = await fetch(url); if (!response.ok) throw new Error("获取记录失败"); const { code, data } = await response.json(); if (code !== 0 || !Array.isArray(data?.list) || typeof data.hasMore !== "boolean" || (!data.list.length && data.hasMore)) { throw new Error("官方接口返回错误或无效分页"); } if (data.list.length > 0) { allRecords.push(...data.list); hasMore = data.hasMore; if (hasMore) { const seqIds = data.list.map((item: { seqId: string }) => Number(item.seqId)); if (seqIds.some((id: number) => !Number.isSafeInteger(id) || id <= 0)) { throw new Error("序号超出安全整数范围或格式无效"); } const nextCursor = Math.min(...seqIds); if (cursor !== null && nextCursor >= cursor) throw new Error("分页游标未前进"); cursor = nextCursor; await new Promise(resolve => setTimeout(resolve, 300)); } } else { hasMore = false; } } } return allRecords; }展開 · 101 行複製这样我们就实现了获取《明日方舟:终末地》的全部卡池的可查询记录。自从《明日方舟:终末地》 1.1 版本后,HGWebview.log 日志文件中不再记录寻访记录链接,导致目前社区相关脚本均已失效。但是依然可以在鹰角网络通行证等页面根据登录后的 loginToken -> oauthToken -> uid -> u8Token 通过 js 来一键拼出可用的寻访记录链接,具体方法这里不做展开。↩
2026-10-06 更新:本文最初写于开服时,而目前官方 API 返回的数据结构、相关数据的获取和处理都经过了较大变化。现补上赠礼机制、重构池等信息。
今天《明日方舟:终末地》公测了。体验了一段时间之后,想着将抽卡数据导入抽卡分析应用中。但是可能是游戏刚开服的缘故,找了一轮都没能找到导出抽卡数据的工具,最终只能自己动手实现这个功能。下面分享主要思路,如果你需要实现这个功能希望对你有所帮助。
URL 里都有什么
首先,和其他游戏一样,我们可以通过抓包软件抓取或者一些更方便的方法1获取到这样的抽卡记录链接:
角色池
针对角色池,我们主要关注 pool_type 和 seq_id 这两个参数:
pool_type 是卡池枚举值,可以通过下面 API 获取抽卡记录页面提供的角色池:
返回数据:
目前仅能取如下卡池之一:
而与原神,鸣潮等游戏不同,终末地的抽卡记录链接通常带有 seq_id 参数。
通过观察上面两个不同卡池的记录,我们可以发现 seq_id 参数的一些特征:
根据这些特征我们可以知道:在游戏里的抽卡记录展示页中,我们从第一页开始往后翻(从新记录到旧记录)的过程就是抽卡记录链接 seq_id 参数递减的过程。
在链接返回的抽卡记录中,还会带有一个 hasMore 参数。其代表的是当前返回结果的最小 seqId 之下是否还有数据,反映到抽卡页面就是 是否还能翻下一页。
此外,终末地的卡池有赠礼机制。当期特许寻访累计达到 60 次,会额外获得 1 本寻访情报书,接口也会添加一条 kind: "gift_intel_book" 的奖励记录。在处理抽卡数据的时候需要对其进行过滤,否则会出现接口返回的记录条数与抽卡次数不一致。
武器池
与角色池相似,武器池同样可以通过两个 API 获取记录:
获取武器池列表
先通过下面的链接获取用户存在抽卡记录的武器池列表:
返回的数据结构:
这里可以看到武器池分为几种类型:
这里有意思的是,武器限定池的 weapon 前缀拼写为了 wepon
获取武器抽卡记录
获取具体武器池的抽卡记录链接与角色池抽卡记录链接格式有所不同,武器池的抽卡记录链接将 pool_id 参数代替了 pool_type 参数:
其返回的数据结构为:
武器记录的字段与角色记录略有不同:
武器池的 seq_id 特性与角色池相同,所有武器子卡池共享同一条 seqId 序列。
至此,我们已经基本搞清楚了《明日方舟:终末地》抽卡记录链接的逻辑。
主要思路
根据上面的介绍,我们能构想出通过一个有效的终末地抽卡记录链接来获取当前可以查询的所有记录的方法:
角色池
武器池
代码实现
这样我们就实现了获取《明日方舟:终末地》的全部卡池的可查询记录。