PamGram/models/wiki/weapon.py
2022-09-01 12:20:00 +08:00

144 lines
4.7 KiB
Python

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')),
)