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;
|
||||
}
|
||||
|
||||
let reg = /#?(.+)(命座|天赋|技能|资料)$/, msg = e.msg;
|
||||
let reg = /#?(.+)(命座|命之座|天赋|技能|资料)$/, msg = e.msg;
|
||||
let ret = reg.exec(msg);
|
||||
|
||||
if (!ret && !ret[1]) {
|
||||
if (!ret && !ret[1] && !ret[2]) {
|
||||
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", {
|
||||
save_id: "天赋" + char.name,
|
||||
...char,
|
||||
mode,
|
||||
line: getLineData(char),
|
||||
_char: `/meta/character/${char.name}/`
|
||||
});
|
||||
|
2
index.js
2
index.js
@ -22,7 +22,7 @@ let rule = {
|
||||
reg: "^#深渊(第?.{1,2}层)?(角色)?出场(率|统计)*$",
|
||||
},
|
||||
wiki: {
|
||||
reg: "^#.*(天赋|技能|资料)$",
|
||||
reg: "^#.*(天赋|技能|命座|命之座|资料)$",
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -39,10 +39,10 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{if mode == "talent"}}
|
||||
|
||||
{{each talent skill type}}
|
||||
<div class="talent-box">
|
||||
|
||||
<div class="talent-detail">
|
||||
<div class="talent-line">
|
||||
<div class="talent-icon">
|
||||
@ -92,7 +92,6 @@
|
||||
{{/each}}
|
||||
|
||||
<div class="talent-box">
|
||||
|
||||
<div class="talent-detail">
|
||||
{{each passive pass}}
|
||||
<div class="talent-line">
|
||||
@ -109,6 +108,27 @@
|
||||
{{/each}}
|
||||
</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>
|
||||
|
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