mirror of
https://github.com/PaiGramTeam/HonkaiStarRailWikiDataParser.git
synced 2024-11-16 06:25:25 +00:00
✨ support: light cones
This commit is contained in:
parent
f572c25e89
commit
32d47617ee
@ -114,6 +114,7 @@ async def fetch_avatars_infos():
|
||||
|
||||
async def dump_avatars(path: Path):
|
||||
data = [avatar.dict() for avatar in all_avatars]
|
||||
data.sort(key=lambda x: x["id"])
|
||||
async with aiofiles.open(path, "w", encoding="utf-8") as f:
|
||||
await f.write(ujson.dumps(data, indent=4, ensure_ascii=False))
|
||||
|
||||
|
120
func/fetch_light_cones.py
Normal file
120
func/fetch_light_cones.py
Normal file
@ -0,0 +1,120 @@
|
||||
import asyncio
|
||||
import re
|
||||
from pathlib import Path
|
||||
from typing import List, Dict
|
||||
|
||||
import aiofiles
|
||||
import ujson
|
||||
from bs4 import BeautifulSoup
|
||||
|
||||
from func.client import client
|
||||
from func.fetch_materials import all_materials_map, all_materials_name
|
||||
from func.url import info_url
|
||||
from models.enums import Quality, Destiny
|
||||
from models.light_cone import LightCone, LightConePromote, LightConeItem
|
||||
from models.wiki import Children
|
||||
|
||||
all_light_cones: List[LightCone] = []
|
||||
all_light_cones_map: Dict[int, LightCone] = {}
|
||||
all_light_cones_name: Dict[str, LightCone] = {}
|
||||
|
||||
|
||||
async def fetch_light_cones(data: Children):
|
||||
for content in data.list:
|
||||
m_destiny = Destiny(re.findall(r'命途/(.*?)\\', content.ext)[0])
|
||||
m_quality = Quality(re.findall(r'星级/(.*?)\\', content.ext)[0])
|
||||
light_cone = LightCone(
|
||||
id=content.content_id,
|
||||
name=content.title,
|
||||
desc=content.summary,
|
||||
icon=content.icon,
|
||||
big_pic="",
|
||||
quality=m_quality,
|
||||
destiny=m_destiny,
|
||||
promote=[],
|
||||
)
|
||||
all_light_cones.append(light_cone)
|
||||
all_light_cones_map[light_cone.id] = light_cone
|
||||
all_light_cones_name[light_cone.name] = light_cone
|
||||
|
||||
|
||||
def parse_promote(light_cone: LightCone, soup: BeautifulSoup) -> None:
|
||||
"""解析光锥突破数据"""
|
||||
mater = soup.find("div", {"data-part": "material"})
|
||||
trs = mater.find_all("tr")
|
||||
required_levels = [20, 30, 40, 50, 60, 70]
|
||||
max_level = [30, 40, 50, 60, 70, 80]
|
||||
for i in range(0, min(len(trs), 6)):
|
||||
promote = LightConePromote(
|
||||
required_level=required_levels[i],
|
||||
max_level=max_level[i],
|
||||
items=[],
|
||||
)
|
||||
materials = trs[i].find_all("li", {"class": "obc-tmpl__material-item"})
|
||||
for material in materials:
|
||||
try:
|
||||
mid = int(re.findall(r"content/(\d+)/detail", material.find("a").get("href"))[0])
|
||||
except AttributeError:
|
||||
continue
|
||||
name = material.find("p", {"class": "obc-tmpl__material-name"}).text
|
||||
item = all_materials_map.get(mid)
|
||||
if not item:
|
||||
item = all_materials_name.get(name)
|
||||
try:
|
||||
count = int(material.find("span", {"class": "obc-tmpl__material-num"}).text)
|
||||
except (AttributeError, ValueError):
|
||||
count = 1
|
||||
if name == "信用点":
|
||||
promote.coin = count
|
||||
elif item:
|
||||
promote.items.append(
|
||||
LightConeItem(
|
||||
item=item,
|
||||
count=count,
|
||||
)
|
||||
)
|
||||
else:
|
||||
print(f"unknown material: {mid}: {name}")
|
||||
light_cone.promote.append(promote)
|
||||
|
||||
|
||||
async def fetch_info(light_cone: LightCone):
|
||||
print(f"Fetch light_cone info: {light_cone.id}: {light_cone.name}")
|
||||
params = {
|
||||
'app_sn': 'sr_wiki',
|
||||
'content_id': str(light_cone.id),
|
||||
}
|
||||
resp = await client.get(info_url, params=params)
|
||||
data = resp.json()["data"]["content"]["contents"][0]["text"]
|
||||
soup = BeautifulSoup(data, "lxml")
|
||||
table = soup.find("table", {"class": "obc-tml-light-table--pc"})
|
||||
tr = table.find_all("tr")[-1]
|
||||
td = tr.find_all("td")[-1]
|
||||
light_cone.desc = td.get_text().strip()
|
||||
pic_td = soup.find("td", {"class": "obc-tmpl-character__avatar"})
|
||||
light_cone.big_pic = pic_td.find("img").get("src")
|
||||
parse_promote(light_cone, soup)
|
||||
|
||||
|
||||
async def fetch_light_cones_infos():
|
||||
tasks = []
|
||||
for light_cone in all_light_cones:
|
||||
tasks.append(fetch_info(light_cone))
|
||||
await asyncio.gather(*tasks)
|
||||
|
||||
|
||||
async def dump_light_cones(path: Path):
|
||||
data = [light_cone.dict() for light_cone in all_light_cones]
|
||||
data.sort(key=lambda x: x["id"])
|
||||
async with aiofiles.open(path, "w", encoding="utf-8") as f:
|
||||
await f.write(ujson.dumps(data, indent=4, ensure_ascii=False))
|
||||
|
||||
|
||||
async def read_light_cones(path: Path):
|
||||
async with aiofiles.open(path, "r", encoding="utf-8") as f:
|
||||
data = ujson.loads(await f.read())
|
||||
for light_cone in data:
|
||||
m = LightCone(**light_cone)
|
||||
all_light_cones.append(m)
|
||||
all_light_cones_map[m.id] = m
|
||||
all_light_cones_name[m.name] = m
|
@ -78,6 +78,7 @@ async def fetch_materials_infos():
|
||||
|
||||
async def dump_materials(path: Path):
|
||||
data = [material.dict() for material in all_materials]
|
||||
data.sort(key=lambda x: x["id"])
|
||||
async with aiofiles.open(path, "w", encoding="utf-8") as f:
|
||||
await f.write(ujson.dumps(data, indent=4, ensure_ascii=False))
|
||||
|
||||
|
23
main.py
23
main.py
@ -2,15 +2,20 @@ import asyncio
|
||||
from pathlib import Path
|
||||
from func.fetch_all import get_list
|
||||
from func.fetch_avatars import fetch_avatars, fetch_avatars_infos, dump_avatars, read_avatars
|
||||
from func.fetch_light_cones import fetch_light_cones, fetch_light_cones_infos, dump_light_cones, read_light_cones
|
||||
from func.fetch_materials import fetch_materials, fetch_materials_infos, dump_materials, read_materials
|
||||
|
||||
data_path = Path("data")
|
||||
data_path.mkdir(exist_ok=True)
|
||||
|
||||
|
||||
async def main(override: bool = True):
|
||||
async def main(
|
||||
override_materials: bool = True,
|
||||
override_avatars: bool = True,
|
||||
override_light_cones: bool = True,
|
||||
):
|
||||
main_data = await get_list()
|
||||
if override:
|
||||
if override_materials:
|
||||
await fetch_materials(main_data[4])
|
||||
await fetch_materials(main_data[5], "消耗品")
|
||||
await fetch_materials(main_data[8], "任务道具")
|
||||
@ -20,10 +25,22 @@ async def main(override: bool = True):
|
||||
await dump_materials(data_path / "materials.json")
|
||||
else:
|
||||
await read_materials(data_path / "materials.json")
|
||||
if override_avatars:
|
||||
await fetch_avatars(main_data[0])
|
||||
await fetch_avatars_infos()
|
||||
await dump_avatars(data_path / "avatars.json")
|
||||
else:
|
||||
await read_avatars(data_path / "avatars.json")
|
||||
if override_light_cones:
|
||||
await fetch_light_cones(main_data[1])
|
||||
await fetch_light_cones_infos()
|
||||
await dump_light_cones(data_path / "light_cones.json")
|
||||
else:
|
||||
await read_light_cones(data_path / "light_cones.json")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
asyncio.run(main())
|
||||
override_materials = True
|
||||
override_avatars = True
|
||||
override_light_cones = True
|
||||
asyncio.run(main(override_materials, override_avatars, override_light_cones))
|
||||
|
@ -1,23 +1,19 @@
|
||||
# 光锥
|
||||
from pydantic import BaseModel
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from models.enums import Quality, Destiny
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from models.material import Material
|
||||
|
||||
|
||||
class LightConeItem(BaseModel):
|
||||
item: "Material"
|
||||
item: Material
|
||||
"""物品"""
|
||||
count: int
|
||||
"""数量"""
|
||||
|
||||
|
||||
class LightConePromote(BaseModel):
|
||||
required_level: int = 0
|
||||
required_level: int
|
||||
"""突破所需等级"""
|
||||
promote_level: int = 0
|
||||
"""突破等级"""
|
||||
|
Loading…
Reference in New Issue
Block a user