mirror of
https://github.com/yoimiya-kokomi/miao-plugin.git
synced 2024-11-16 04:35:42 +00:00
增加角色信息的爬取工具
This commit is contained in:
parent
3a2f626907
commit
0680636359
12
apps/wiki.js
12
apps/wiki.js
@ -18,18 +18,24 @@ export async function wiki(e, { render }) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let reg = /#?(.+)(命座|天赋|技能|资料)$/, msg = e.msg;
|
let reg = /#?(.+)(命座|命之座|天赋|技能|资料)$/, msg = e.msg;
|
||||||
let ret = reg.exec(msg);
|
let ret = reg.exec(msg);
|
||||||
|
|
||||||
if (!ret && !ret[1]) {
|
if (!ret && !ret[1] && !ret[2]) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let char = Character.get(ret[1]);
|
let mode = "talent";
|
||||||
|
if (/命/.test(ret[2])) {
|
||||||
|
mode = "cons";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let char = Character.get(ret[1]);
|
||||||
let base64 = await render("wiki", "character", {
|
let base64 = await render("wiki", "character", {
|
||||||
save_id: "天赋" + char.name,
|
save_id: "天赋" + char.name,
|
||||||
...char,
|
...char,
|
||||||
|
mode,
|
||||||
line: getLineData(char),
|
line: getLineData(char),
|
||||||
_char: `/meta/character/${char.name}/`
|
_char: `/meta/character/${char.name}/`
|
||||||
});
|
});
|
||||||
|
2
index.js
2
index.js
@ -22,7 +22,7 @@ let rule = {
|
|||||||
reg: "^#深渊(第?.{1,2}层)?(角色)?出场(率|统计)*$",
|
reg: "^#深渊(第?.{1,2}层)?(角色)?出场(率|统计)*$",
|
||||||
},
|
},
|
||||||
wiki: {
|
wiki: {
|
||||||
reg: "^#.*(天赋|技能|资料)$",
|
reg: "^#.*(天赋|技能|命座|命之座|资料)$",
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -39,10 +39,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{{if mode == "talent"}}
|
||||||
|
|
||||||
{{each talent skill type}}
|
{{each talent skill type}}
|
||||||
<div class="talent-box">
|
<div class="talent-box">
|
||||||
|
|
||||||
<div class="talent-detail">
|
<div class="talent-detail">
|
||||||
<div class="talent-line">
|
<div class="talent-line">
|
||||||
<div class="talent-icon">
|
<div class="talent-icon">
|
||||||
@ -92,7 +92,6 @@
|
|||||||
{{/each}}
|
{{/each}}
|
||||||
|
|
||||||
<div class="talent-box">
|
<div class="talent-box">
|
||||||
|
|
||||||
<div class="talent-detail">
|
<div class="talent-detail">
|
||||||
{{each passive pass}}
|
{{each passive pass}}
|
||||||
<div class="talent-line">
|
<div class="talent-line">
|
||||||
@ -109,6 +108,27 @@
|
|||||||
{{/each}}
|
{{/each}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{if mode == "cons"}}
|
||||||
|
<div class="talent-box">
|
||||||
|
<div class="talent-detail">
|
||||||
|
{{each cons con idx}}
|
||||||
|
<div class="talent-line">
|
||||||
|
<div class="talent-icon">
|
||||||
|
<img src="{{_res_path}}{{_char}}/cons_{{idx}}.png"/>
|
||||||
|
</div>
|
||||||
|
<div class="talent-info">
|
||||||
|
<strong class="talent-name">{{con.name}}</strong>
|
||||||
|
<div class="talent-desc">
|
||||||
|
{{con.desc}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
<div class="logo">Create By Yunzai-Bot & Miao-Plugin</div>
|
<div class="logo">Create By Yunzai-Bot & Miao-Plugin</div>
|
||||||
</div>
|
</div>
|
||||||
|
218
tools/char-data-sprider.js
Normal file
218
tools/char-data-sprider.js
Normal file
@ -0,0 +1,218 @@
|
|||||||
|
import fs from "fs";
|
||||||
|
import cheerio from "cheerio";
|
||||||
|
import lodash from "lodash";
|
||||||
|
import fetch from "node-fetch";
|
||||||
|
|
||||||
|
const _path = process.cwd();
|
||||||
|
|
||||||
|
let txt = fs.readFileSync(`${_path}/plugins/miao-plugin/tools/test.txt`);
|
||||||
|
|
||||||
|
function getBasic($) {
|
||||||
|
let ret = {}
|
||||||
|
// 采集基础信息
|
||||||
|
ret.name = $("#scroll_card_item").next("table").find("tr:first td:eq(1)").text();
|
||||||
|
let basic = $(".data_cont_wrapper table:first");
|
||||||
|
let title = function (title) {
|
||||||
|
return basic.find(`td:contains('${title}')`).next("td").text();
|
||||||
|
}
|
||||||
|
ret.title = title("Title");
|
||||||
|
ret.allegiance = title("Allegiance");
|
||||||
|
ret.weapon = title("Weapon Type");
|
||||||
|
ret.britydah = title("Birthday");
|
||||||
|
ret.astro = title("Astrolabe Name");
|
||||||
|
ret.cncv = title("Chinese Seiyuu");
|
||||||
|
ret.jpcv = title("Japanese Seiyuu");
|
||||||
|
ret.desc = title("In-game Description");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getStat($) {
|
||||||
|
// 采集属性信息
|
||||||
|
let stat = $("#beta_scroll_stat").next(".skilldmgwrapper").find("table");
|
||||||
|
let attrs = [], idx = 4;
|
||||||
|
stat.find("tr:first td:gt(0)").each(function (i) {
|
||||||
|
let title = $(this).text();
|
||||||
|
if (title === "Ascension") {
|
||||||
|
idx = i + 1;
|
||||||
|
console.log(idx);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
attrs.push($(this).text())
|
||||||
|
})
|
||||||
|
let lvs = [], lvStat = {};
|
||||||
|
stat.find("tr:gt(0)").each(function (i) {
|
||||||
|
let tr = $(this), lvl = tr.find("td:first").text();
|
||||||
|
lvs.push(lvl);
|
||||||
|
let data = [];
|
||||||
|
tr.find(`td:lt(${idx})`).each(function (i) {
|
||||||
|
if (i > 0) {
|
||||||
|
data.push($(this).text())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
lvStat[lvl] = data;
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
lvs,
|
||||||
|
stat: attrs,
|
||||||
|
detail: lvStat
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTalents($, eq) {
|
||||||
|
let root = $("#beta_scroll_attack_talent");
|
||||||
|
let info = root.nextAll(`.item_main_table:eq(${eq})`);
|
||||||
|
|
||||||
|
let title = info.find("tr:first td:eq(1)").text();
|
||||||
|
let icon = info.find("tr:first td:first img").attr("data-src");
|
||||||
|
|
||||||
|
// 说明
|
||||||
|
let desc = info.find("tr:eq(1) td div.skill_desc_layout").html();
|
||||||
|
desc = desc.replace(/<color=[^>]*>/g, "");
|
||||||
|
desc = desc.replace(/<\/color=[^>]*>/g, "");
|
||||||
|
desc = desc.replace(/<span class=[^>]*>/g, "<strong>");
|
||||||
|
desc = desc.replace(/<\/span>/g, "</strong>");
|
||||||
|
desc = desc.split("<br>");
|
||||||
|
lodash.forEach(desc, (txt, i) => {
|
||||||
|
desc[i] = lodash.trim(txt);
|
||||||
|
})
|
||||||
|
|
||||||
|
// detail
|
||||||
|
let detail = root.nextAll(`.skilldmgwrapper:eq(${eq})`).find("table");
|
||||||
|
let lvs = [], details = [];
|
||||||
|
detail.find("tr:first td").each(function (i) {
|
||||||
|
if (i > 0) {
|
||||||
|
lvs.push($(this).text())
|
||||||
|
}
|
||||||
|
});
|
||||||
|
detail.find("tr:gt(0)").each(function () {
|
||||||
|
let title = $(this).find("td:eq(0)").text();
|
||||||
|
let values = [], isSame = true;
|
||||||
|
$(this).find("td:gt(0)").each(function (i) {
|
||||||
|
let val = $(this).text();
|
||||||
|
values.push(val);
|
||||||
|
if (i > 0 && values[0] !== val) {
|
||||||
|
isSame = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
details.push({
|
||||||
|
title, isSame, values
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
title,
|
||||||
|
icon,
|
||||||
|
desc,
|
||||||
|
details,
|
||||||
|
lvs
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
let getPassive = function ($) {
|
||||||
|
let table = $("#beta_scroll_passive_talent").next("table")
|
||||||
|
let ret = [];
|
||||||
|
table.find("tr").each(function (idx) {
|
||||||
|
if (idx % 2 === 0) {
|
||||||
|
let ds = {};
|
||||||
|
ds.icon = $(this).find("td:first img").attr("data-src");
|
||||||
|
ds.title = $(this).find("td:eq(1)").text();
|
||||||
|
ret[idx / 2] = ds;
|
||||||
|
} else {
|
||||||
|
ret[(idx - 1) / 2].desc = $(this).find("td").text();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
let getCons = function ($) {
|
||||||
|
let table = $("#beta_scroll_constellation").next("table")
|
||||||
|
let ret = [];
|
||||||
|
table.find("tr").each(function (idx) {
|
||||||
|
if (idx % 2 === 0) {
|
||||||
|
let ds = {};
|
||||||
|
ds.icon = $(this).find("td:first img").attr("data-src");
|
||||||
|
ds.title = $(this).find("td:eq(1)").text();
|
||||||
|
ret[idx / 2] = ds;
|
||||||
|
} else {
|
||||||
|
ret[(idx - 1) / 2].desc = $(this).find("td").text();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
let getImgs = function ($) {
|
||||||
|
let cont = $("#scroll_gallery").next(".homepage_index_cont");
|
||||||
|
let img = function (idx, _cont) {
|
||||||
|
return (_cont || cont).find(`.gallery_content_cont:eq(${idx}) a`).attr("href");
|
||||||
|
}
|
||||||
|
let card = $("#scroll_name_card").nextAll(".homepage_index_cont:first");
|
||||||
|
return {
|
||||||
|
face: img(0),
|
||||||
|
side: img(1),
|
||||||
|
gacha_card: img(2),
|
||||||
|
gacha_splash: img(3),
|
||||||
|
profile: img(1, card),
|
||||||
|
party: img(2, card),
|
||||||
|
char: $("#live_beta_checker").nextAll(".item_main_table:first").find("tr:first td:first img").attr("data-src")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let getCharData = function (url, key, name = '') {
|
||||||
|
|
||||||
|
|
||||||
|
const $ = cheerio.load(txt);
|
||||||
|
let ret = getBasic($);
|
||||||
|
if (name) {
|
||||||
|
ret.name = name;
|
||||||
|
}
|
||||||
|
ret.lvStat = getStat($);
|
||||||
|
ret.talent = {
|
||||||
|
a: getTalents($, 0),
|
||||||
|
e: getTalents($, 1),
|
||||||
|
q: getTalents($, 2)
|
||||||
|
}
|
||||||
|
ret.passive = getPassive($);
|
||||||
|
ret.cons = getCons($);
|
||||||
|
ret.imgs = getImgs($);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function down() {
|
||||||
|
const url = "https://genshin.honeyhunterworld.com/db/char/characters/?lang=CHS";
|
||||||
|
let req = await fetch(url);
|
||||||
|
let txt = await req.text();
|
||||||
|
let $ = cheerio.load(txt);
|
||||||
|
let char = $(".char_sea_cont:first");
|
||||||
|
|
||||||
|
char.each(function () {
|
||||||
|
let url = $(this).find("a:first").attr("href");
|
||||||
|
let keyRet = /\/char\/(\w*)\//.exec(url);
|
||||||
|
|
||||||
|
|
||||||
|
if (keyRet && keyRet[1]) {
|
||||||
|
let key = keyRet[1],
|
||||||
|
tRet = /traveler_(girl|boy)_(\w*)/.exec(key),
|
||||||
|
name;
|
||||||
|
if (tRet) {
|
||||||
|
if (tRet[1] === "girl") {
|
||||||
|
let name = { anemo: "风", geo: "岩", electro: "雷" }[tRet[2]] + "主";
|
||||||
|
getCharData(url, key, name);
|
||||||
|
} else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(url, key);
|
||||||
|
//let data = await getCharData(url, key, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
down();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
148
tools/char-init.js
Normal file
148
tools/char-init.js
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
import Data from "../components/Data.js";
|
||||||
|
import lodash from "lodash";
|
||||||
|
import { Character } from "../components/models.js";
|
||||||
|
import fs from "fs";
|
||||||
|
|
||||||
|
import { roleId, abbr } from "../../../config/genshin/roleId.js";
|
||||||
|
|
||||||
|
let roleIdMap = {};
|
||||||
|
lodash.forEach(roleId, (names, id) => {
|
||||||
|
roleIdMap[names[0]] = id;
|
||||||
|
})
|
||||||
|
|
||||||
|
let _root = process.cwd();
|
||||||
|
let characterMeta = Data.readJSON("./plugins/miao-plugin/components/meta", "characters.json");
|
||||||
|
let characters = {};
|
||||||
|
let pathName = process.cwd() + "/plugins/miao-plugin/resources/meta/character/";
|
||||||
|
|
||||||
|
// 获取指定角色的Meta信息
|
||||||
|
const getMetaData = function (name) {
|
||||||
|
if (!characterMeta[name]) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
const metaCfg = { lowerFirstKey: true },
|
||||||
|
meta = characterMeta[name];
|
||||||
|
|
||||||
|
// 处理基础信息
|
||||||
|
let ret = Data.getData(meta, "Name,Key,Title,desc:Description,astro:AstrolabeName", metaCfg);
|
||||||
|
|
||||||
|
ret.star = /4star/.test(meta.Star) ? 4 : 5;
|
||||||
|
|
||||||
|
let weaponid = /s_(\d*).png$/.exec(meta.Weapon);
|
||||||
|
if (weaponid) {
|
||||||
|
ret.weapon = {
|
||||||
|
233101: "长柄武器",
|
||||||
|
33101: "单手剑",
|
||||||
|
43101: "法器",
|
||||||
|
163101: "双手剑",
|
||||||
|
213101: "弓"
|
||||||
|
}[weaponid[1]]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 处理图像信息
|
||||||
|
//ret.img = Data.getData(meta, "Weapon,Element,City,Profile,GachaCard,GachaSplash,Source", metaCfg);
|
||||||
|
|
||||||
|
// 处理元素
|
||||||
|
let elemRet = /([^\/]*).png$/.exec(meta.Element);
|
||||||
|
console.log(elemRet[1]);
|
||||||
|
if (elemRet && elemRet[1]) {
|
||||||
|
ret.elem = elemRet[1];
|
||||||
|
ret.element = elemName[ret.elem];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理属性
|
||||||
|
ret.stat = Data.getData(meta, "hp:BaseHP,atk:BaseATK,def:BaseDEF,growStat:AscensionStat,growValue:AscensionStatValue", metaCfg);
|
||||||
|
ret.lvStat = lodash.map(meta.CharStat, (d) => Data.getData(d, "Name,Values", metaCfg));
|
||||||
|
|
||||||
|
if (/Mende/.test(meta.City)) {
|
||||||
|
ret.city = "蒙德"
|
||||||
|
} else if (/Liyue/.test(meta.City)) {
|
||||||
|
ret.city = "璃月";
|
||||||
|
} else if (/Daoqi/.test(meta.City)) {
|
||||||
|
ret.city = "稻妻";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理材料
|
||||||
|
let itemKey = lodash.map("talent,boss,gemStone,Local,monster,weekly".split(","), (a) => `${a}:${lodash.upperFirst(a)}.Name`);
|
||||||
|
ret.item = Data.getData(meta, itemKey, metaCfg)
|
||||||
|
|
||||||
|
// 处理天赋
|
||||||
|
ret.talent = {
|
||||||
|
a: getTalentData(meta.NormalAttack),
|
||||||
|
e: getTalentData(meta.TalentE),
|
||||||
|
q: getTalentData(meta.TalentQ),
|
||||||
|
};
|
||||||
|
|
||||||
|
// 处理其他天赋
|
||||||
|
ret.passive = lodash.map(meta.PassiveTalents, (d) => Data.getData(d, "Name,desc:Description", metaCfg))
|
||||||
|
|
||||||
|
// 处理命座信息
|
||||||
|
let cons = {};
|
||||||
|
lodash.forEach(meta.Constellation, (data, key) => {
|
||||||
|
cons[key.replace("Constellation", "")] = Data.getData(data, "Name,desc:Description", metaCfg);
|
||||||
|
})
|
||||||
|
ret.cons = cons;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取Meta中的天赋信息
|
||||||
|
const getTalentData = function (data) {
|
||||||
|
let ret = Data.getData(data, "Name,desc:Description", { lowerFirstKey: true });
|
||||||
|
let attr = [], table = [], tableKeys;
|
||||||
|
|
||||||
|
lodash.forEach(data.Table, (tr) => {
|
||||||
|
let tmp = { name: tr.Name }, isTable = true, isDef = false, lastVal;
|
||||||
|
|
||||||
|
// 检查当前行是否是表格数据
|
||||||
|
lodash.forEach(tr.Values, (v) => {
|
||||||
|
// 如果为空则退出循环
|
||||||
|
if (v === "") {
|
||||||
|
isTable = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof (lastVal) === "undefined") {
|
||||||
|
// 设定初始值
|
||||||
|
lastVal = v;
|
||||||
|
} else if (lastVal != v) {
|
||||||
|
// 如果与初始值不一样,则标记退出循环
|
||||||
|
isDef = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (isTable && isDef) {
|
||||||
|
if (!tableKeys) {
|
||||||
|
tableKeys = lodash.keys(tr.Values);
|
||||||
|
}
|
||||||
|
tmp.value = lodash.map(tableKeys, (k) => tr.Values[k])
|
||||||
|
table.push(tmp);
|
||||||
|
} else {
|
||||||
|
tmp.value = lastVal;
|
||||||
|
attr.push(tmp)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
ret.attr = attr;
|
||||||
|
ret.table = table;
|
||||||
|
ret.tableKeys = tableKeys;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
lodash.forEach(characterMeta, (c) => {
|
||||||
|
let meta = Character.getMetaData(c.Name);
|
||||||
|
let data = {
|
||||||
|
id: roleIdMap[meta.name],
|
||||||
|
key: meta.key,
|
||||||
|
name: meta.name,
|
||||||
|
abbr: abbr[meta.name] || meta.name,
|
||||||
|
city: meta.city
|
||||||
|
};
|
||||||
|
lodash.defaults(data, meta)
|
||||||
|
Data.createDir(pathName, data.name)
|
||||||
|
fs.writeFileSync(`${pathName}${data.name}/data.json`, JSON.stringify(data, "", "\t"));
|
||||||
|
characters[data.id] = { id: data.id, key: data.key, name: meta.name };
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
fs.writeFileSync(`${pathName}index.json`, JSON.stringify(characters, "", "\t"));
|
Loading…
Reference in New Issue
Block a user