mirror of
https://github.com/PaiGramTeam/Gift-Code-Web.git
synced 2024-11-21 14:48:27 +00:00
Support show gift code
This commit is contained in:
parent
01fb1f9e16
commit
d034fe0a72
2
.gitignore
vendored
2
.gitignore
vendored
@ -157,4 +157,4 @@ cython_debug/
|
|||||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||||
#.idea/
|
.idea/
|
||||||
|
55
add.py
Normal file
55
add.py
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
from sys import argv
|
||||||
|
from datetime import datetime
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
from models.code import CodeList, Code, Reward
|
||||||
|
|
||||||
|
data_path = Path("data")
|
||||||
|
custom_path = data_path / "custom.json"
|
||||||
|
|
||||||
|
|
||||||
|
def add(code: str, expire_str: str, rewards_str: List[str]) -> Code:
|
||||||
|
expire = datetime.strptime(expire_str, "%Y-%m-%d")
|
||||||
|
expire = expire.replace(hour=23, minute=59, second=59, microsecond=999999)
|
||||||
|
rewards = []
|
||||||
|
for reward_str in rewards_str:
|
||||||
|
reward_list = reward_str.split(":")
|
||||||
|
rewards.append(
|
||||||
|
Reward(
|
||||||
|
name=reward_list[0],
|
||||||
|
cnt=int(reward_list[1])
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return Code(
|
||||||
|
code=code,
|
||||||
|
expire=int(expire.timestamp() * 1000),
|
||||||
|
reward=rewards,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
try:
|
||||||
|
add_type = argv[1]
|
||||||
|
if add_type not in ["main", "over"]:
|
||||||
|
raise IndexError
|
||||||
|
code = add(argv[2], argv[3], argv[4:])
|
||||||
|
with open(custom_path, "r", encoding="utf-8") as f:
|
||||||
|
custom: CodeList = CodeList.parse_raw(f.read())
|
||||||
|
if add_type == "main":
|
||||||
|
main_codes = [i.code for i in custom.main]
|
||||||
|
if code.code in main_codes:
|
||||||
|
raise ValueError("Duplicate code")
|
||||||
|
custom.main.append(code)
|
||||||
|
else:
|
||||||
|
over_codes = [i.code for i in custom.over]
|
||||||
|
if code.code in over_codes:
|
||||||
|
raise ValueError("Duplicate code")
|
||||||
|
custom.over.append(code)
|
||||||
|
custom.main.sort(key=lambda x: x.expire, reverse=True)
|
||||||
|
custom.over.sort(key=lambda x: x.expire, reverse=True)
|
||||||
|
with open(custom_path, "w", encoding="utf-8") as f:
|
||||||
|
f.write(custom.json(indent=4, ensure_ascii=False))
|
||||||
|
except IndexError:
|
||||||
|
print("Usage: python add.py [main/over] [code] [expire] [rewards...]")
|
||||||
|
print("Example: python add.py main code 2023-11-1 星琼:1 信用点:1000")
|
189
data/code.html
Normal file
189
data/code.html
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Dark Responsive Page with Tabs</title>
|
||||||
|
|
||||||
|
<!-- 新 Bootstrap5 核心 CSS 文件 -->
|
||||||
|
<link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/5.1.1/css/bootstrap.min.css">
|
||||||
|
|
||||||
|
<!-- 最新的 Bootstrap5 核心 JavaScript 文件 -->
|
||||||
|
<script src="https://cdn.staticfile.org/twitter-bootstrap/5.1.1/js/bootstrap.bundle.min.js"></script>
|
||||||
|
|
||||||
|
<!-- custom styles -->
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
background-color: #222;
|
||||||
|
color: #222;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
color: #eee;
|
||||||
|
margin-top: 50px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-title {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar {
|
||||||
|
background-color: #333;
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-brand {
|
||||||
|
color: #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-content {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-title {
|
||||||
|
color: #eee;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<header>
|
||||||
|
<h1>《崩坏:星穹铁道》兑换码</h1>
|
||||||
|
</header>
|
||||||
|
<div style="height: 30px;"></div>
|
||||||
|
<main class="container">
|
||||||
|
<ul class="nav nav-tabs">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link active" data-bs-toggle="tab" href="#tab1">国服(官服)</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" data-bs-toggle="tab" href="#tab2">国际服</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div class="tab-content">
|
||||||
|
<div class="tab-pane active" id="tab1">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12 col-md-8 offset-md-2">
|
||||||
|
<h2 class="table-title">未到期</h2>
|
||||||
|
<table class="table table-dark table-striped">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>兑换码</th>
|
||||||
|
<th>奖励</th>
|
||||||
|
<th>到期时间</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="main-true">
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<h2 class="table-title">已到期</h2>
|
||||||
|
<table class="table table-dark table-striped">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>兑换码</th>
|
||||||
|
<th>奖励</th>
|
||||||
|
<th>到期时间</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="main-false">
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="tab-pane" id="tab2">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12 col-md-8 offset-md-2">
|
||||||
|
<h2 class="table-title">未到期</h2>
|
||||||
|
<table class="table table-dark table-striped">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>兑换码</th>
|
||||||
|
<th>奖励</th>
|
||||||
|
<th>到期时间</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="over-true">
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<h2 class="table-title">已到期</h2>
|
||||||
|
<table class="table table-dark table-striped">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>兑换码</th>
|
||||||
|
<th>奖励</th>
|
||||||
|
<th>到期时间</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="over-false">
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
<div style="height: 100px;"></div>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<nav class="navbar">
|
||||||
|
<div class="container-fluid">
|
||||||
|
<a class="navbar-brand" href="#">PaiGramTeam</a>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function addRow(tableId, data) {
|
||||||
|
let now = new Date();
|
||||||
|
let expire_time = new Date(data.expire);
|
||||||
|
if (now > expire_time) {
|
||||||
|
tableId += "-false";
|
||||||
|
} else {
|
||||||
|
tableId += "-true";
|
||||||
|
}
|
||||||
|
let table = document.getElementById(tableId);
|
||||||
|
let new_tr = document.createElement("tr");
|
||||||
|
let code = document.createElement("td");
|
||||||
|
code.innerHTML = data.code;
|
||||||
|
let reward = document.createElement("td");
|
||||||
|
data.reward.forEach(function (item) {
|
||||||
|
let p = document.createElement("p");
|
||||||
|
p.innerHTML = item.name + " x" + item.cnt;
|
||||||
|
reward.appendChild(p);
|
||||||
|
});
|
||||||
|
let expire = document.createElement("td");
|
||||||
|
expire.innerHTML = expire_time.toLocaleString();
|
||||||
|
new_tr.appendChild(code);
|
||||||
|
new_tr.appendChild(reward);
|
||||||
|
new_tr.appendChild(expire);
|
||||||
|
table.appendChild(new_tr);
|
||||||
|
}
|
||||||
|
|
||||||
|
fetch('code.json')
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
for (let key in data) {
|
||||||
|
for (let value in data[key]) {
|
||||||
|
addRow(key, data[key][value]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => console.error(error));
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
214
data/code.json
Normal file
214
data/code.json
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
{
|
||||||
|
"main": [
|
||||||
|
{
|
||||||
|
"code": "MIYOUSHE2023",
|
||||||
|
"reward": [
|
||||||
|
{
|
||||||
|
"name": "星琼",
|
||||||
|
"cnt": 60
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"expire": 1686402166000
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"over": [
|
||||||
|
{
|
||||||
|
"code": "BSN2EWMHA4RP",
|
||||||
|
"reward": [
|
||||||
|
{
|
||||||
|
"name": "星琼",
|
||||||
|
"cnt": 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "信用点",
|
||||||
|
"cnt": 10000
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"expire": 4102415999999
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "HSRVER10JYTGHC",
|
||||||
|
"reward": [
|
||||||
|
{
|
||||||
|
"name": "星琼",
|
||||||
|
"cnt": 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "信用点",
|
||||||
|
"cnt": 10000
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"expire": 4102415999999
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "STARRAILGIFT",
|
||||||
|
"reward": [
|
||||||
|
{
|
||||||
|
"name": "星琼",
|
||||||
|
"cnt": 50
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "信用点",
|
||||||
|
"cnt": 10000
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"expire": 4102415999999
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "SURPRISE1024",
|
||||||
|
"reward": [
|
||||||
|
{
|
||||||
|
"name": "星琼",
|
||||||
|
"cnt": 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "冒险记录",
|
||||||
|
"cnt": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "疾速粉尘",
|
||||||
|
"cnt": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "信用点",
|
||||||
|
"cnt": 5000
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"expire": 1686070799999
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "ZTPTNMTX8LUF",
|
||||||
|
"reward": [
|
||||||
|
{
|
||||||
|
"name": "星琼",
|
||||||
|
"cnt": 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "信用点",
|
||||||
|
"cnt": 50000
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"expire": 1685206799999
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "8A6T6LBFQ4D3",
|
||||||
|
"reward": [
|
||||||
|
{
|
||||||
|
"name": "星琼",
|
||||||
|
"cnt": 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "漫游指南",
|
||||||
|
"cnt": 5
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"expire": 1685206799999
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "DB7A64BW8LC7",
|
||||||
|
"reward": [
|
||||||
|
{
|
||||||
|
"name": "星琼",
|
||||||
|
"cnt": 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "提纯以太",
|
||||||
|
"cnt": 4
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"expire": 1685206799999
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "CS75WMP976AK",
|
||||||
|
"reward": [
|
||||||
|
{
|
||||||
|
"name": "星琼",
|
||||||
|
"cnt": 100
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"expire": 1685206799999
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "HSRVER10XEDLFE",
|
||||||
|
"reward": [
|
||||||
|
{
|
||||||
|
"name": "星琼",
|
||||||
|
"cnt": 50
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "信用点",
|
||||||
|
"cnt": 10000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "漫游指南",
|
||||||
|
"cnt": 2
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"expire": 1683565199999
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "2T7BP4JVEBT7",
|
||||||
|
"reward": [
|
||||||
|
{
|
||||||
|
"name": "信用点",
|
||||||
|
"cnt": 5000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "冒险记录",
|
||||||
|
"cnt": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "凝缩以太",
|
||||||
|
"cnt": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "大宇宙炒饭",
|
||||||
|
"cnt": 3
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"expire": 1683392399999
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "HSRGRANDOPEN1",
|
||||||
|
"reward": [
|
||||||
|
{
|
||||||
|
"name": "星琼",
|
||||||
|
"cnt": 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "信用点",
|
||||||
|
"cnt": 5000
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"expire": 1682787599999
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "HSRGRANDOPEN2",
|
||||||
|
"reward": [
|
||||||
|
{
|
||||||
|
"name": "星琼",
|
||||||
|
"cnt": 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "漫游指南",
|
||||||
|
"cnt": 5
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"expire": 1682787599999
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "HSRGRANDOPEN3",
|
||||||
|
"reward": [
|
||||||
|
{
|
||||||
|
"name": "星琼",
|
||||||
|
"cnt": 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "提纯以太",
|
||||||
|
"cnt": 4
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"expire": 1682787599999
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
15
data/custom.json
Normal file
15
data/custom.json
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"main": [
|
||||||
|
{
|
||||||
|
"code": "MIYOUSHE2023",
|
||||||
|
"reward": [
|
||||||
|
{
|
||||||
|
"name": "星琼",
|
||||||
|
"cnt": 60
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"expire": 1689695999999
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"over": []
|
||||||
|
}
|
33
main.py
Normal file
33
main.py
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
from typing import List
|
||||||
|
|
||||||
|
from models.code import CodeList, Code
|
||||||
|
from models.honkai import get_code
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
data_path = Path("data")
|
||||||
|
custom_path = data_path / "custom.json"
|
||||||
|
code_path = data_path / "code.json"
|
||||||
|
|
||||||
|
|
||||||
|
def merge_code(over: List[Code], custom: CodeList) -> CodeList:
|
||||||
|
over_codes = [i for i in over]
|
||||||
|
custom_over_codes = [i.code for i in custom.over]
|
||||||
|
for code in over_codes:
|
||||||
|
if code.code in custom_over_codes:
|
||||||
|
continue
|
||||||
|
custom.over.append(code)
|
||||||
|
return custom
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
over = get_code()
|
||||||
|
with open(custom_path, "r", encoding="utf-8") as f:
|
||||||
|
custom = CodeList.parse_raw(f.read())
|
||||||
|
custom = merge_code(over, custom)
|
||||||
|
with open(code_path, "w", encoding="utf-8") as f:
|
||||||
|
f.write(custom.json(indent=4, ensure_ascii=False))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
0
models/__init__.py
Normal file
0
models/__init__.py
Normal file
19
models/code.py
Normal file
19
models/code.py
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
from typing import List
|
||||||
|
|
||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
|
||||||
|
class Reward(BaseModel):
|
||||||
|
name: str
|
||||||
|
cnt: int
|
||||||
|
|
||||||
|
|
||||||
|
class Code(BaseModel):
|
||||||
|
code: str
|
||||||
|
reward: List[Reward]
|
||||||
|
expire: int
|
||||||
|
|
||||||
|
|
||||||
|
class CodeList(BaseModel):
|
||||||
|
main: List[Code]
|
||||||
|
over: List[Code]
|
81
models/honkai.py
Normal file
81
models/honkai.py
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
from datetime import datetime
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
from httpx import get
|
||||||
|
from bs4 import BeautifulSoup, Tag
|
||||||
|
from .code import Code, Reward
|
||||||
|
|
||||||
|
|
||||||
|
url = "https://honkai.gg/cn/codes"
|
||||||
|
reward_map = {
|
||||||
|
"Stellar Jade": "星琼",
|
||||||
|
"Credit": "信用点",
|
||||||
|
"Credits": "信用点",
|
||||||
|
"Traveler's Guide": "漫游指南",
|
||||||
|
"Refined Aether": "提纯以太",
|
||||||
|
"Adventure Log": "冒险记录",
|
||||||
|
"Dust of Alacrity": "疾速粉尘",
|
||||||
|
"Condensed Aether": "凝缩以太",
|
||||||
|
"Cosmic Fried Rice": "大宇宙炒饭",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def parse_reward(reward: List[str]) -> Reward:
|
||||||
|
try:
|
||||||
|
name = reward_map.get(reward[0])
|
||||||
|
if not name:
|
||||||
|
print("Unknown reward: ", reward[0])
|
||||||
|
name = reward[0]
|
||||||
|
return Reward(
|
||||||
|
name=name,
|
||||||
|
cnt=int(reward[1]),
|
||||||
|
)
|
||||||
|
except ValueError:
|
||||||
|
print("Bad reward data: ", reward)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_code(tr: Tag) -> Code:
|
||||||
|
tds = tr.find_all("td")
|
||||||
|
code = tds[0].text.strip()
|
||||||
|
expire = tds[2].text.strip()
|
||||||
|
if expire.endswith("?"):
|
||||||
|
expire = datetime(2099, 12, 31, 23, 59, 59, 999999)
|
||||||
|
else:
|
||||||
|
expires = expire.split(" - ")
|
||||||
|
day = expires[1].split(" ")[-1]
|
||||||
|
month = expires[0].split(" ")[0]
|
||||||
|
try:
|
||||||
|
if " " not in expires[1]:
|
||||||
|
raise ValueError
|
||||||
|
month = expires[1].split(" ")[0]
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
now = datetime.now()
|
||||||
|
expire = datetime.strptime(f"{day} {month}", "%d %b")
|
||||||
|
expire = expire.replace(year=now.year, hour=23, minute=59, second=59, microsecond=999999)
|
||||||
|
expire = int(expire.timestamp() * 1000)
|
||||||
|
rewards = []
|
||||||
|
for reward in tds[1].find_all("div", {"class": "flex"}):
|
||||||
|
reward_div = reward.text.strip().split("\xa0x ")
|
||||||
|
parsed_reward = parse_reward(reward_div)
|
||||||
|
if parsed_reward:
|
||||||
|
rewards.append(parsed_reward)
|
||||||
|
for reward in tds[1].find_all("a"):
|
||||||
|
reward_a = reward.text.strip().split(" x ")
|
||||||
|
parsed_reward = parse_reward(reward_a)
|
||||||
|
if parsed_reward:
|
||||||
|
rewards.append(parsed_reward)
|
||||||
|
return Code(code=code, reward=rewards, expire=expire)
|
||||||
|
|
||||||
|
|
||||||
|
def get_code():
|
||||||
|
html = get(url).text
|
||||||
|
soup = BeautifulSoup(html, "lxml")
|
||||||
|
tables = soup.find_all("table")
|
||||||
|
codes = []
|
||||||
|
for table in tables:
|
||||||
|
trs = table.find_all("tr")[1:]
|
||||||
|
for tr in trs:
|
||||||
|
codes.append(parse_code(tr))
|
||||||
|
codes.sort(key=lambda x: x.expire, reverse=True)
|
||||||
|
return codes
|
4
requirements.txt
Normal file
4
requirements.txt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
pydantic
|
||||||
|
httpx
|
||||||
|
beautifulsoup4
|
||||||
|
lxml
|
Loading…
Reference in New Issue
Block a user