MibooGram/models/wiki/weapon.py

144 lines
4.7 KiB
Python
Raw Normal View History

import itertools
import re
from typing import List, Optional, Tuple, Union
from bs4 import BeautifulSoup
from httpx import URL
from models.wiki.base import Model, SCRAPE_HOST, WikiModel
from models.wiki.other import AttributeType, WeaponType
__all__ = ['Weapon', 'WeaponAffix', 'WeaponAttribute']
class WeaponAttribute(Model):
"""武器词条"""
type: AttributeType
value: str
class WeaponAffix(Model):
"""武器技能
Attributes:
name: 技能名
description: 技能描述
"""
name: str
description: List[str]
class WeaponState(Model):
level: str
ATK: float
bonus: Optional[str]
class WeaponIcon(Model):
icon: str
awakened: str
gacha: str
class Weapon(WikiModel):
"""武器
Attributes:
type: 武器类型
attack: 基础攻击力
attribute:
affix: 武器技能
description: 描述
ascension: 突破材料
story: 武器故事
"""
weapon_type: WeaponType
attack: float
attribute: Optional[WeaponAttribute]
affix: Optional[WeaponAffix]
description: str
ascension: List[str]
story: Optional[str]
stats: List[WeaponState]
@staticmethod
def scrape_urls() -> List[URL]:
return [SCRAPE_HOST.join(f"fam_{i.lower()}/?lang=CHS") for i in WeaponType.__members__]
@classmethod
async def _parse_soup(cls, soup: BeautifulSoup) -> 'Weapon':
"""解析武器页"""
soup = soup.select('.wp-block-post-content')[0]
tables = soup.find_all('table')
table_rows = tables[0].find_all('tr')
def get_table_text(row_num: int) -> str:
"""一个快捷函数,用于返回表格对应行的最后一个单元格中的文本"""
return table_rows[row_num].find_all('td')[-1].text.replace('\xa0', '')
def find_table(select: str):
"""一个快捷函数,用于寻找对应表格头的表格"""
return list(filter(lambda x: select in ' '.join(x.attrs['class']), tables))
id_ = re.findall(r'/img/(.*?)_gacha', str(table_rows[0]))[0]
weapon_type = WeaponType[get_table_text(1).split(',')[-1].strip()]
name = get_table_text(0)
rarity = len(table_rows[2].find_all('img'))
attack = float(get_table_text(4))
ascension = [re.findall(r'/(.*)/', tag.attrs['href'])[0] for tag in table_rows[-1].find_all('a')]
if rarity > 2: # 如果是 3 星及其以上的武器
attribute = WeaponAttribute(
type=AttributeType.convert(
tables[2].find('thead').find('tr').find_all('td')[2].text.split(' ')[1]
),
value=get_table_text(6)
)
affix = WeaponAffix(name=get_table_text(7), description=[
i.find_all('td')[1].text for i in tables[3].find_all('tr')[1:]
])
if len(tables) < 11:
description = get_table_text(-1)
else:
description = get_table_text(9)
if story_table := find_table('quotes'):
story = story_table[0].text.strip()
else:
story = None
else: # 如果是 2 星及其以下的武器
attribute = affix = None
description = get_table_text(5)
story = tables[-1].text.strip()
stats = []
for row in tables[2].find_all('tr')[1:]:
cells = row.find_all('td')
if rarity > 2:
stats.append(WeaponState(level=cells[0].text, ATK=cells[1].text, bonus=cells[2].text))
else:
stats.append(WeaponState(level=cells[0].text, ATK=cells[1].text))
return Weapon(
id=id_, name=name, rarity=rarity, attack=attack, attribute=attribute, affix=affix, weapon_type=weapon_type,
story=story, stats=stats, description=description, ascension=ascension
)
@classmethod
async def get_name_list(cls, *, with_url: bool = False) -> List[Union[str, Tuple[str, URL]]]:
# 重写此函数的目的是名字去重,例如单手剑页面中有三个 “「一心传」名刀”
name_list = [i async for i in cls._name_list_generator(with_url=with_url)]
if with_url:
return [
(i[0], list(i[1])[0][1]) for i in itertools.groupby(name_list, lambda x: x[0])
]
else:
return [i[0] for i in itertools.groupby(name_list, lambda x: x)]
@property
def icon(self) -> WeaponIcon:
return WeaponIcon(
icon=str(SCRAPE_HOST.join(f'/img/{self.id}.webp')),
awakened=str(SCRAPE_HOST.join(f'/img/{self.id}_awaken_icon.webp')),
gacha=str(SCRAPE_HOST.join(f'/img/{self.id}_gacha_icon.webp')),
)