我正在使用一个api,它为我提供了61个条目,这些条目包含在一个嵌入在for循环中的不一致中。
由于所有这些都计划包含在一个使用DiscordUtils分页的discord机器人中,我需要让它为每10个条目设置一个嵌入,以避免太长的消息/ 2000个字符的消息。
目前我用来做我的循环的是:https://api.nepmia.fr/spc/ (我推荐你的浏览器使用一个解析扩展,否则它会有点难读)
但是我想要创建的是类似这样的东西:https://api.nepmia.fr/spc/formated/
因此,我可以在不同的嵌入中迭代每个范围,然后使用分页。
我使用TinyDB生成我之前使用此脚本显示的JSON文件:
import urllib.request, json
from shutil import copyfile
from termcolor import colored
from tinydb import TinyDB, Query
db = TinyDB("/home/nepmia/Myazu/db/db.json")
def api_get():
print(colored("[Myazu]","cyan"), colored("Fetching WynncraftAPI...", "white"))
try:
with urllib.request.urlopen("https://api.wynncraft.com/public_api.php?action=guildStats&command=Spectral%20Cabbage") as u1:
api_1 = json.loads(u1.read().decode())
count = 0
if members := api_1.get("members"):
print(colored("[Myazu]","cyan"),
colored("Got expecteded answer, starting saving process.", "white"))
for member in members:
nick = member.get("name")
ur2 = f"https://api.wynncraft.com/v2/player/{nick}/stats"
u2 = urllib.request.urlopen(ur2)
api_2 = json.loads(u2.read().decode())
data = api_2.get("data")
for item in data:
meta = item.get("meta")
playtime = meta.get("playtime")
print(colored("[Myazu]","cyan"),
colored("Saving playtime for player", "white"),
colored(f"{nick}...","green"))
db.insert({"username": nick, "playtime": playtime})
count += 1
else:
print(colored("[Myazu]","cyan"),
colored("Unexpected answer from WynncraftAPI [ERROR 1]", "white"))
except:
print(colored("[Myazu]","cyan"),
colored("Unhandled error in saving process [ERROR 2]", "white"))
finally:
print(colored("[Myazu]","cyan"),
colored(f"Finished saving data for", "white"),
colored(f"{count}", "green"),
colored("players.", "white"))但这只会创建一个这样的范围:https://api.nepmia.fr/spc/
我想要的是这样的东西:https://api.nepmia.fr/spc/formated/
感谢您的帮助!
PS:对不起,对你的眼睛来说,我仍然是Python的新手,所以我知道我做的事情并不是很正确:
发布于 2020-11-29 19:24:45
为了跟踪评论,您不应该以特定于您希望如何将结果从数据库返回到不同API的格式将项存储在数据库中,因为这将使在其他上下文中进行查询变得更加困难,等等。
如果您想对数据库中的项进行分页,最好在查询时执行此操作。
根据文档,您可以通过直接在DB上迭代来迭代TinyDB数据库中的所有文档,如下所示:
for doc in db:
...对于任何可迭代对象,您可以使用enumerate函数将索引关联到每个项目,如下所示:
for idx, doc in enumerate(db):
...如果希望索引像示例中那样以1开头,那么只需使用idx + 1即可。
最后,要对结果进行分页,您需要一些函数来以固定大小的批处理返回迭代器中的项,比如this question或其他地方的众多解决方案中的一个。例如,给定一个函数chunked(iter, size),你可以这样做:
pages = enumerate(chunked(enumerate(db), 10))然后,list(pages)给出了一个类似于[(page_num, [(player_num, player), ...]的元组列表。
列表列表和您想要的列表之间的唯一区别是您似乎想要如下所示的字典结构
{'range1': {'1': {...}, '2': {...}, ...}, 'range2': {'11': {...}, ...}}这与列表列表没有什么不同;唯一的区别是您使用字典键为集合中的每一项提供数字索引,而不是在列表结构中隐含的索引。有很多方法可以让你从一个列表到这个列表。我认为最简单的方法是使用(嵌套的)字典理解:
{f'range{page_num + 1}': {str(player_num + 1): player for player_num, player in page}
for page_num, page in pages}这将以您想要的格式输出。
发布于 2020-11-30 19:28:14
感谢@Iguananaut的宝贵帮助。
最后,我使用生成器从您的解决方案中制作了类似的东西。
def chunker(seq, size):
for i in range(0, len(seq), size):
yield seq[i:i+size]
def embed_creator(embeds):
pages = []
current_page = None
for i, chunk in enumerate(chunker(embeds, 10)):
current_page = discord.Embed(
title=f'**SPC** Last week online time',
color=3903947)
for elt in chunk:
current_page.add_field(
name=elt.get("username"),
value=elt.get("play_output"),
inline=False)
current_page.set_footer(
icon_url="https://cdn.discordapp.com/icons/513160124219523086/a_3dc65aae06b2cf7bddcb3c33d7a5ecef.gif?size=128",
text=f"{i + 1} / {ceil(len(embeds) / 10)}"
)
pages.append(current_page)
current_page = None
return pages使用embed_creator,我生成了一个名为pages的列表,我可以简单地与DiscordUtils分页器一起使用。
https://stackoverflow.com/questions/65059122
复制相似问题