数据源基于绝区零官方提供的代理人养成指南,登录完成后按下F12键打开开发者工具粘贴一键代码直接批量获取代理人驱动盘练度信息。
关于获取后的数据...想必有大用吧...可以做练度分析、练度评分,还有我一开始设计脚本时设想的根据角色练度信息来制定每日每周的训练计划
这肯定是很好的,但是这肯定需要收集大量资料、收集各种已有的训练方案、以及驱动盘练度评级算法...
等哪天想起来再慢慢实现吧...

以下是压缩为一行用于生产的版本,您可以直接复制粘贴使用
JavaScript
javascript:(async()=>{const b="https://act-api-takumi.mihoyo.com/event/nap_cultivate_tool",l="https://api-takumi.mihoyo.com/common/badge/v1/login/info",c=t=>t?.replace(/<[^>]*>/g,"").replace(/\\n/g,"")||"",j=(u,o={})=>fetch(u,{credentials:"include",...o}).then(r=>r.json()),u=await j(`${l}?game_biz=nap_cn&lang=zh-cn`),d=document.cookie.match(/DEVICEFP=(\w+)/)?.[1];if(!u.data?.game_uid||!d)return console.error("缺少 uid 或 device_fp");const g=u.data.game_uid,f=a=>j(`${b}/user/avatar_basic_list?uid=${g}®ion=prod_gf_cn`,{headers:{"x-rpc-device_fp":d}}),q=(a,k)=>j(`${b}/user/batch_avatar_detail_v2?uid=${g}®ion=prod_gf_cn`,{method:"POST",headers:{"x-rpc-device_fp":d},body:JSON.stringify({avatar_list:k})}),m=({avatar:e,equip:t,weapon:n})=>({role:{level:e.level,name:e.name_mi18n,full_name:e.full_name_mi18n,camp_name:e.camp_name_mi18n,profession:e.avatar_profession,rarity:e.rarity,group_icon:e.group_icon_path,avatar_icon:e.hollow_icon_path,properties:e.properties.map(({property_name:r,final:i})=>({name:r,val:i})),ranks:e.ranks.map(({name:r,desc:i,is_unlocked:s})=>({name:r,desc:c(i),unlocked:s}))},equips:t?.map(({level:r,name:i,icon:s,rarity:o,invalid_property_cnt:p,equipment_type:h,properties:w,main_properties:x,equip_suit:y})=>({level:r,name:i,icon:s,rarity:o,invalid_property:p,num:h,properties:w.map(({property_name:v,base:k,level:B,valid:U,add:L})=>({name:v,val:k,level:B,valid:U,add:L})),main_properties:{name:x[0].property_name,val:x[0].base,level:x[0].level,valid:x[0].valid,add:x[0].add},suit:{name:y.name,desc1:y.desc1,desc2:c(y.desc2)}})),weapon:n&&{level:n.level,name:n.name,star:n.star,icon:n.icon,rarity:n.rarity,talent_title:n.talent_title,talent_content:c(n.talent_content),profession:n.profession,property:{...n.properties[0]},main_properties:{...n.main_properties[0]}}});let s=await f();const a=s.data.list.filter(({unlocked:r})=>r).map(({avatar:r})=>({avatar_id:r.id}));console.log(`已获取 ${a.length} 位角色,正在加载详情...`);let o=[];for(let r=0;r<a.length;r+=10)o.push(a.slice(r,r+10));const P=await Promise.all(o.map(r=>q(0,r))),S=P.flatMap(r=>r.data.list.map(m));console.log("处理完成:",S)})();
若你有更多需求,想要获取更多数据,可根据以下源码自行修改:
JavaScript
/**
* 绝区零角色练度数据提取 — 可读版
* 作者:doupoa 和 ChatGPT 优化与重构
* 功能:
* - 自动获取当前登录账号 UID
* - 读取所有已解锁角色
* - 批量获取装备与音擎(武器)信息
* - 输出洗净结构的完整练度数据
*/
(async () => {
const API_BASE = "https://act-api-takumi.mihoyo.com/event/nap_cultivate_tool";
const API_LOGIN = "https://api-takumi.mihoyo.com/common/badge/v1/login/info";
/** 清理文本中的 HTML 标签与转义换行 */
const cleanText = (text) =>
text?.replace(/<[^>]*>/g, "").replace(/\\n/g, "") || "";
/** 包装 fetch 为 JSON 解析 */
const fetchJSON = (url, options = {}) =>
fetch(url, { credentials: "include", ...options }).then((res) => res.json());
/** 获取当前登录账号 UID */
const getGameUID = async () =>
(await fetchJSON(`${API_LOGIN}?game_biz=nap_cn&lang=zh-cn`)).data
?.game_uid;
/** 从 cookie 获取设备指纹 */
const getDeviceFP = () => document.cookie.match(/DEVICEFP=(\w+)/)?.[1];
/** 获取基础角色列表 */
const getBasicList = (uid, fp) =>
fetchJSON(`${API_BASE}/user/avatar_basic_list?uid=${uid}®ion=prod_gf_cn`, {
headers: { "x-rpc-device_fp": fp },
});
/** 分批请求角色详情每批最多 10 个 */
const getEquipBatch = (uid, batch, fp) =>
fetchJSON(
`${API_BASE}/user/batch_avatar_detail_v2?uid=${uid}®ion=prod_gf_cn`,
{
method: "POST",
headers: { "x-rpc-device_fp": fp },
body: JSON.stringify({ avatar_list: batch }),
}
);
/** 数据清洗逻辑:将接口返回转化为更简洁的数据结构 */
const processEquipData = ({
avatar,
equip,
weapon,
}) => ({
// ---- 角色基础信息 ----
role: {
level: avatar.level,
name: avatar.name_mi18n,
full_name: avatar.full_name_mi18n,
camp_name: avatar.camp_name_mi18n,
profession: avatar.avatar_profession,
rarity: avatar.rarity,
group_icon: avatar.group_icon_path,
avatar_icon: avatar.hollow_icon_path,
// 属性(例如生命、攻击等)
properties: avatar.properties.map(({ property_name, final }) => ({
name: property_name,
val: final,
})),
// 潜能/角色 rank(清除 HTML 标签)
ranks: avatar.ranks.map(({ name, desc, is_unlocked }) => ({
name,
desc: cleanText(desc),
unlocked: is_unlocked,
})),
},
// ---- 驱动盘信息 ----
equips: equip?.map(
({
level,
name,
icon,
rarity,
invalid_property_cnt,
equipment_type,
properties,
main_properties,
equip_suit,
}) => ({
level,
name,
icon,
rarity,
invalid_property: invalid_property_cnt,
num: equipment_type,
// 子属性
properties: properties.map(
({ property_name, base, level, valid, add }) => ({
name: property_name,
val: base,
level,
valid,
add,
})
),
// 主属性
main_properties: {
name: main_properties[0].property_name,
val: main_properties[0].base,
level: main_properties[0].level,
valid: main_properties[0].valid,
add: main_properties[0].add,
},
// 套装信息
suit: {
name: equip_suit.name,
desc1: equip_suit.desc1,
desc2: cleanText(equip_suit.desc2),
},
})
),
// ---- 音擎信息 ----
weapon:
weapon && {
level: weapon.level,
name: weapon.name,
star: weapon.star,
icon: weapon.icon,
rarity: weapon.rarity,
talent_title: weapon.talent_title,
talent_content: cleanText(weapon.talent_content),
profession: weapon.profession,
property: { ...weapon.properties[0] },
main_properties: { ...weapon.main_properties[0] },
},
});
// ========================
// 主流程开始
// ========================
const uid = await getGameUID();
const device_fp = getDeviceFP();
if (!uid || !device_fp) {
console.error("❌ 无法读取 UID 或 DEVICEFP,可能未登录!");
return;
}
console.log("🎮 当前登录 UID:", uid);
// 获取基础角色列表
const basicData = await getBasicList(uid, device_fp);
const avatarList = basicData.data.list
.filter((i) => i.unlocked)
.map((i) => ({ avatar_id: i.avatar.id }));
console.log(`已找到 ${avatarList.length} 位已解锁角色,开始获取装备详情...`);
// 将角色 ID 分批,每批最多 10 个
const batches = [];
for (let i = 0; i < avatarList.length; i += 10)
batches.push(avatarList.slice(i, i + 10));
// 并发请求所有批次
const detailResponses = await Promise.all(
batches.map((batch) => getEquipBatch(uid, batch, device_fp))
);
// 清洗所有批次的数据
const allResults = detailResponses.flatMap((res) =>
res.data.list.map(processEquipData)
);
console.log("🎉 已成功提取所有角色数据(结构已清洗):");
console.log(allResults);
})();
绝区零
发表回复