mirror of
https://github.com/PaiGramTeam/PamGram.git
synced 2024-11-29 09:07:13 +00:00
9327e69f9d
`model` → `models`
211 lines
8.8 KiB
Python
211 lines
8.8 KiB
Python
import os
|
||
from enum import Enum
|
||
from typing import Optional
|
||
|
||
import httpx
|
||
import ujson
|
||
from bs4 import BeautifulSoup
|
||
|
||
from .helpers import get_headers, get_id_form_url
|
||
|
||
|
||
class WeaponType(Enum):
|
||
Sword = "sword" # 单手剑
|
||
Claymore = "claymore" # 双手剑
|
||
PoleArm = "polearm" # 长柄武器
|
||
Bow = "bow" # 弓
|
||
Catalyst = "catalyst" # 法器
|
||
|
||
|
||
class Weapons:
|
||
IGNORE_WEAPONS_ID = [
|
||
"1001", "1101", "1406",
|
||
"2001", "2101", "2204", "2406", "2407",
|
||
"3001", "3101", "3204", "3404",
|
||
"4001", "4101", "4201", "4403", "4405", "4406",
|
||
"5001", "5101", "5201", "5404", "5404", "5405",
|
||
] # 忽略的武器包括一星、二星武器,beta表格内无名武器,未上架到正服的武器
|
||
|
||
# 根地址
|
||
ROOT_URL = "https://genshin.honeyhunterworld.com"
|
||
|
||
TEXT_MAPPING = {
|
||
"Type": "类型",
|
||
"Rarity": "Rarity",
|
||
"Base Attack": "基础攻击力"
|
||
}
|
||
|
||
WEAPON_TYPE_MAPPING = {
|
||
"Sword": "https://genshin.honeyhunterworld.com/img/skills/s_33101.png", # 单手剑
|
||
"Claymore": "https://genshin.honeyhunterworld.com/img/skills/s_163101.png", # 双手剑
|
||
"Polearm": "https://genshin.honeyhunterworld.com/img/skills/s_233101.png", # 长枪
|
||
"Bow": "https://genshin.honeyhunterworld.com/img/skills/s_213101.png", # 弓箭
|
||
"Catalyst": "https://genshin.honeyhunterworld.com/img/skills/s_43101.png", # 法器
|
||
}
|
||
|
||
def __init__(self):
|
||
self.client = httpx.AsyncClient(headers=get_headers())
|
||
project_path = os.path.dirname(__file__)
|
||
characters_file = os.path.join(project_path, "metadata", "ascension.json")
|
||
monster_file = os.path.join(project_path, "metadata", "monster.json")
|
||
elite_file = os.path.join(project_path, "metadata", "elite.json")
|
||
with open(characters_file, "r", encoding="utf-8") as f:
|
||
self._ascension_json: dict = ujson.load(f)
|
||
with open(monster_file, "r", encoding="utf-8") as f:
|
||
self._monster_json: dict = ujson.load(f)
|
||
with open(elite_file, "r", encoding="utf-8") as f:
|
||
self._elite_json: dict = ujson.load(f)
|
||
|
||
async def _get_soup(self, url: str) -> Optional[BeautifulSoup]:
|
||
request = await self.client.get(url)
|
||
return BeautifulSoup(request.text, "lxml")
|
||
|
||
async def get_weapon_url_list(self, weapon_type: WeaponType):
|
||
weapon_url_list = []
|
||
url = self.ROOT_URL + f"/db/weapon/{weapon_type.value}/?lang=CHS"
|
||
soup = await self._get_soup(url)
|
||
weapon_table = soup.find("span", {"class": "item_secondary_title"},
|
||
string="Released (Codex) Weapons").find_next_sibling()
|
||
weapon_table_rows = weapon_table.find_all("tr")
|
||
for weapon_table_row in weapon_table_rows:
|
||
content = weapon_table_row.find_all("td")[2]
|
||
if content.find("a") is not None:
|
||
weapon_url = self.ROOT_URL + content.find("a")["href"]
|
||
weapon_id = str(get_id_form_url(weapon_url))
|
||
if weapon_id not in self.IGNORE_WEAPONS_ID:
|
||
weapon_url_list.append(weapon_url)
|
||
return weapon_url_list
|
||
|
||
async def get_all_weapon_url(self):
|
||
all_weapon_url = []
|
||
temp_data = await self.get_weapon_url_list(WeaponType.Bow)
|
||
all_weapon_url.extend(temp_data)
|
||
temp_data = await self.get_weapon_url_list(WeaponType.Sword)
|
||
all_weapon_url.extend(temp_data)
|
||
temp_data = await self.get_weapon_url_list(WeaponType.PoleArm)
|
||
all_weapon_url.extend(temp_data)
|
||
temp_data = await self.get_weapon_url_list(WeaponType.Catalyst)
|
||
all_weapon_url.extend(temp_data)
|
||
temp_data = await self.get_weapon_url_list(WeaponType.Claymore)
|
||
all_weapon_url.extend(temp_data)
|
||
return all_weapon_url
|
||
|
||
@staticmethod
|
||
def get_weapon_info_template():
|
||
weapon_info_dict = {
|
||
"name": "",
|
||
"description": "",
|
||
"source_img": "",
|
||
"atk":
|
||
{
|
||
"min": 0,
|
||
"max": 999999,
|
||
"name": "基础攻击力"
|
||
},
|
||
"secondary":
|
||
{
|
||
"min": 0.1,
|
||
"max": 999999.9,
|
||
"name": ""
|
||
},
|
||
"star":
|
||
{
|
||
"value": -1,
|
||
"icon": ""
|
||
},
|
||
"type":
|
||
{
|
||
"name": "",
|
||
"icon": ""
|
||
},
|
||
"passive_ability":
|
||
{
|
||
"name": "",
|
||
"description": ""
|
||
}
|
||
}
|
||
materials_dict = {
|
||
"name": "",
|
||
"star": {
|
||
"value": 0,
|
||
"icon": ""
|
||
},
|
||
"city": "",
|
||
"icon": ""
|
||
}
|
||
weapon_info_dict["materials"] = {
|
||
"ascension": materials_dict,
|
||
"elite": materials_dict,
|
||
"monster": materials_dict,
|
||
}
|
||
return weapon_info_dict
|
||
|
||
async def get_weapon_info(self, url: str):
|
||
weapon_info_dict = self.get_weapon_info_template()
|
||
soup = await self._get_soup(url)
|
||
weapon_content = soup.find("div", {"class": "wrappercont"})
|
||
data = weapon_content.find("div", {"class": "data_cont_wrapper", "style": "display: block"})
|
||
weapon_info = data.find("table", {"class": "item_main_table"})
|
||
weapon_name = weapon_content.find("div", {"class": "custom_title"}).text.replace("-", "").replace(" ", "")
|
||
weapon_info_dict["name"] = weapon_name
|
||
weapon_info_row = weapon_info.find_all("tr")
|
||
for weapon_info_ in weapon_info_row:
|
||
content = weapon_info_.find_all("td")
|
||
if len(content) == 3: # 第一行会有三个td,其中一个td是武器图片
|
||
weapon_info_dict["source_img"] = self.ROOT_URL + content[0].find("img",
|
||
{"class": "itempic lazy"})["data-src"]
|
||
weapon_info_dict["type"]["name"] = content[2].text
|
||
weapon_info_dict["type"]["icon"] = self.get_weapon_type(content[2].text)
|
||
elif len(content) == 2:
|
||
if content[0].text == "Rarity":
|
||
weapon_info_dict["star"]["value"] = len(
|
||
content[1].find_all("div", {"class": "sea_char_stars_wrap"}))
|
||
elif content[0].text == "Special (passive) Ability":
|
||
weapon_info_dict["passive_ability"]["name"] = content[1].text
|
||
elif content[0].text == "Special (passive) Ability Description":
|
||
weapon_info_dict["passive_ability"]["description"] = content[1].text
|
||
elif content[0].text == "In-game Description":
|
||
weapon_info_dict["description"] = content[1].text
|
||
elif content[0].text == "Secondary Stat":
|
||
weapon_info_dict["secondary"]["name"] = content[1].text
|
||
|
||
stat_table = data.find("span", {"class": "item_secondary_title"},
|
||
string=" Stat Progression ").find_next_sibling()
|
||
stat_table_row = stat_table.find_all("tr")
|
||
for stat_table_ in stat_table_row:
|
||
content = stat_table_.find_all("td")
|
||
# 通过等级判断
|
||
if content[0].text == "1":
|
||
weapon_info_dict["atk"]["min"] = int(content[1].text)
|
||
weapon_info_dict["secondary"]["min"] = float(content[2].text)
|
||
elif content[0].text == "80+":
|
||
item_hrefs = content[3].find_all("a")
|
||
for item_href in item_hrefs:
|
||
item_id = get_id_form_url(item_href["href"])
|
||
ascension = self.get_ascension(str(item_id))
|
||
if ascension.get("name") is not None:
|
||
weapon_info_dict["materials"]["ascension"] = ascension
|
||
monster = self.get_monster(str(item_id))
|
||
if monster.get("name") is not None:
|
||
weapon_info_dict["materials"]["monster"] = monster
|
||
elite = self.get_elite(str(item_id))
|
||
if elite.get("name") is not None:
|
||
weapon_info_dict["materials"]["elite"] = elite
|
||
elif content[0].text == "90":
|
||
weapon_info_dict["atk"]["max"] = int(content[1].text)
|
||
weapon_info_dict["secondary"]["max"] = float(content[2].text)
|
||
|
||
return weapon_info_dict
|
||
|
||
def get_ascension(self, item_id: str):
|
||
return self._ascension_json.get(item_id, {})
|
||
|
||
def get_monster(self, item_id: str):
|
||
return self._monster_json.get(item_id, {})
|
||
|
||
def get_elite(self, item_id: str):
|
||
return self._elite_json.get(item_id, {})
|
||
|
||
def get_weapon_type(self, weapon_type: str):
|
||
return self.WEAPON_TYPE_MAPPING.get(weapon_type, "")
|