| | |
| | import aiohttp |
| | from bs4 import BeautifulSoup |
| | from typing import List, Dict |
| |
|
| | GENSHIN_API = ( |
| | "https://genshin-impact.fandom.com/api.php" |
| | "?action=parse" |
| | "&page=Promotional_Code" |
| | "&prop=text" |
| | "&format=json" |
| | ) |
| |
|
| | class GenshinCodeLogic: |
| | def __init__(self): |
| | self.session: aiohttp.ClientSession | None = None |
| |
|
| | async def start(self): |
| | if not self.session: |
| | self.session = aiohttp.ClientSession( |
| | headers={"User-Agent": "Mozilla/5.0 (GenshinCodeBot)"} |
| | ) |
| |
|
| | async def stop(self): |
| | if self.session: |
| | await self.session.close() |
| | self.session = None |
| |
|
| | async def fetch_codes(self) -> Dict: |
| | async with self.session.get( |
| | GENSHIN_API, |
| | timeout=aiohttp.ClientTimeout(total=20) |
| | ) as resp: |
| | if resp.status != 200: |
| | return {"count": 0, "cards": []} |
| |
|
| | data = await resp.json() |
| |
|
| | html = data.get("parse", {}).get("text", {}).get("*") |
| | if not html: |
| | return {"count": 0, "cards": []} |
| |
|
| | soup = BeautifulSoup(html, "html.parser") |
| |
|
| | cards: List[Dict] = [] |
| |
|
| | for row in soup.select("table.wikitable tbody tr"): |
| | tds = row.find_all("td") |
| | if len(tds) < 3: |
| | continue |
| |
|
| | code_els = tds[0].find_all("code") |
| | if not code_els: |
| | continue |
| |
|
| | codes = [c.get_text(strip=True) for c in code_els] |
| |
|
| | server = tds[1].get_text(" ", strip=True) |
| |
|
| | rewards = [] |
| | for item in tds[2].select(".item-text"): |
| | text = item.get_text(" ", strip=True) |
| | if text: |
| | rewards.append(text) |
| |
|
| | validity = ( |
| | tds[3].get_text(" ", strip=True) |
| | if len(tds) >= 4 else None |
| | ) |
| |
|
| | cards.append({ |
| | "codes": codes, |
| | "server": server, |
| | "rewards": rewards, |
| | "validity": validity |
| | }) |
| |
|
| | return { |
| | "count": sum(len(card["codes"]) for card in cards), |
| | "cards": cards |
| | } |