Discord机器人!lek命令语法错误及Embed拆分需求求助
问题排查与解决方案
1. "invalid syntax (, line 1)" 语法错误
原因:原send_embed_segments函数中使用str(embed)将Embed对象转为字符串,再用eval解析分段后的字符串,这是错误逻辑。str(discord.Embed)生成的是人类可读的描述文本,并非可解析的Python代码,因此eval会抛出语法错误。
修复方案:放弃字符串转换和eval操作,直接提取Embed的结构化数据(标题、颜色、字段等),拆分后生成新的Embed对象发送。
2. "embed size exceeds maximum size of 6000" 内容过长错误
原因:Discord Embed的总字符限制为6000(包含标题、描述、所有字段的名称和值),药品信息的Embed内容超出了该限制。
修复方案:将原Embed拆分为多个Embed,每个Embed的总字符数控制在6000以内。
完整修正代码
替换原有的send_embed_segments函数,并修复get_tweets中的字符串语法问题:
import discord from discord.ext import commands import requests import json import tweepy import os # 获取脚本所在目录 current_directory = os.path.dirname(os.path.realpath(__file__)) # Twitter API密钥 twitter_consumer_key = "00000" twitter_consumer_secret = "000000000000" twitter_access_token = "00000000000000000" twitter_access_token_secret = "000000000000000" # News API密钥 news_api_key = "98166982a7e4455da7f8f65b95ed50a7" # 专业医疗信息来源列表 medical_sources = [ 'medical-news-today.com', 'sciencedaily.com', 'medscape.com', 'bmj.com', 'nejm.org', 'fda.gov', 'cdc.gov' ] # 配置Twitter API auth = tweepy.OAuthHandler(twitter_consumer_key, twitter_consumer_secret) auth.set_access_token(twitter_access_token, twitter_access_token_secret) twitter_api = tweepy.API(auth) intents = discord.Intents.all() bot = commands.Bot(command_prefix='!', intents=intents) # 机器人允许执行命令的频道ID wybrany_kanal_id = 1172578358589145119 async def send_embed_segments(ctx, original_embed): MAX_EMBED_SIZE = 6000 # 提取原Embed的基础信息 base_info = { "title": original_embed.title, "color": original_embed.color.value, "description": original_embed.description or "" } # 计算初始字符占用(标题+描述) current_total = len(base_info["title"]) + len(base_info["description"]) current_fields = [] for field in original_embed.fields: # 计算当前字段的字符长度 field_length = len(field.name) + len(field.value) # 如果添加当前字段会超出限制,先发送现有内容 if current_total + field_length > MAX_EMBED_SIZE: new_embed = discord.Embed(**base_info) for f in current_fields: new_embed.add_field(name=f["name"], value=f["value"], inline=f["inline"]) await ctx.send(embed=new_embed) # 重置计数器和字段列表 current_total = len(base_info["title"]) + len(base_info["description"]) current_fields = [] # 将字段加入当前列表 current_fields.append({ "name": field.name, "value": field.value, "inline": field.inline }) current_total += field_length # 发送剩余的字段 if current_fields: new_embed = discord.Embed(**base_info) for f in current_fields: new_embed.add_field(name=f["name"], value=f["value"], inline=f["inline"]) await ctx.send(embed=new_embed) @bot.command() async def lek(ctx, *, nazwa_leku): try: if ctx.channel.id != wybrany_kanal_id: await ctx.send('Ta komenda może być używana tylko na określonym kanale.') return # 生成JSON文件路径列表 lista_plikow = [ os.path.join(current_directory, f'drug-label-000{i}-of-0011.json') for i in range(1, 12) ] pierwszy_wynik = None for nazwa_pliku in lista_plikow: with open(nazwa_pliku, 'r', encoding='utf-8') as file: data = json.load(file) found_results = [result for result in data.get('results', []) if nazwa_leku.lower() in result.get('openfda', {}).get('brand_name', [''])[0].lower()] if found_results: pierwszy_wynik = found_results[0] break if pierwszy_wynik: nazwa_handlowa = pierwszy_wynik.get('openfda', {}).get('brand_name', ['Brak informacji'])[0] opis = pierwszy_wynik.get('purpose', ['Brak informacji'])[0] producent = pierwszy_wynik.get('openfda', {}).get('manufacturer_name', ['Brak informacji'])[0] nazwa_generyczna = pierwszy_wynik.get('openfda', {}).get('generic_name', ['Brak informacji'])[0] ndc = pierwszy_wynik.get('openfda', {}).get('product_ndc', ['Brak informacji'])[0] typ_produktu = pierwszy_wynik.get('openfda', {}).get('product_type', ['Brak informacji'])[0] droga_podawania = pierwszy_wynik.get('openfda', {}).get('route', ['Brak informacji'])[0] substancja = pierwszy_wynik.get('openfda', {}).get('substance_name', ['Brak informacji'])[0] cel = pierwszy_wynik.get('purpose', ['Brak informacji'])[0] wskazania_i_uzytkowanie = pierwszy_wynik.get('indications_and_usage', ['Brak informacji'])[0] ostrzezenia = pierwszy_wynik.get('warnings', ['Brak informacji'])[0] zachowaj_poza_zasiegiem_dzieci = pierwszy_wynik.get('keep_out_of_reach_of_children', ['Brak informacji'])[0] dawkowanie_i_podawanie = pierwszy_wynik.get('dosage_and_administration', ['Brak informacji'])[0] przechowywanie_i_obsluga = pierwszy_wynik.get('storage_and_handling', ['Brak informacji'])[0] embed = discord.Embed(title=f'Informacje o leku: {nazwa_leku}', color=0x00ff00) embed.add_field(name='Nazwa handlowa', value=nazwa_handlowa, inline=False) embed.add_field(name='Opis', value=opis, inline=False) embed.add_field(name='Producent', value=producent, inline=False) embed.add_field(name='Nazwa generyczna', value=nazwa_generyczna, inline=False) embed.add_field(name='Numer NDC', value=ndc, inline=False) embed.add_field(name='Typ produktu', value=typ_produktu, inline=False) embed.add_field(name='Droga podawania', value=droga_podawania, inline=False) embed.add_field(name='Substancja', value=substancja, inline=False) embed.add_field(name='Cel', value=cel, inline=False) embed.add_field(name='Wskazania i użycie', value=wskazania_i_uzytkowanie, inline=False) embed.add_field(name='Ostrzeżenia', value=ostrzezenia, inline=False) embed.add_field(name='Zachowaj poza zasięgiem dzieci', value=zachowaj_poza_zasiegiem_dzieci, inline=False) embed.add_field(name='Dawkowanie i podawanie', value=dawkowanie_i_podawanie, inline=False) embed.add_field(name='Przechowywanie i obsługa', value=przechowywanie_i_obsluga, inline=False) await send_embed_segments(ctx, embed) else: await ctx.send(f'Nie znaleziono informacji o leku o nazwie "{nazwa_leku}".') except Exception as e: print(e) await ctx.send('Wystąpił błąd podczas wczytywania informacji o leku z pliku.') @bot.command() async def aktualnosci(ctx): try: sources = ','.join(medical_sources) url = f'https://newsapi.org/v2/top-headlines?sources={sources}&apiKey={news_api_key}' response = requests.get(url) news_data = response.json() if 'articles' in news_data: articles = news_data['articles'] for article in articles[:5]: title = article.get('title', 'Brak tytułu') description = article.get('description', 'Brak opisu') url = article.get('url', '#') embed = discord.Embed(title=title, description=description, url=url, color=0x0000ff) await send_embed_segments(ctx, embed) else: await ctx.send('Nie udało się pobrać aktualności.') except Exception as e: print(e) await ctx.send('Wystąpił błąd podczas pobierania aktualności.') @bot.command() async def get_tweets(ctx, username, count=5): try: tweets = twitter_api.user_timeline(screen_name=username, count=count, tweet_mode="extended") for tweet in tweets: tweet_text = tweet.full_text tweet_url = f"https://twitter.com/{username}/status/{tweet.id}" if username.lower() == 'cdcgov': channel_id = 1172578344911519774 elif username.lower() == 'fda': channel_id = 1172578358589145119 else: channel_id = None if channel_id: channel = bot.get_channel(channel_id) # 修复字符串换行的语法错误 await channel.send(f'Tweet od @{username}:\n{tweet_text}\nWięcej na: {tweet_url}') except Exception as e: print(f'Wystąpił błąd podczas pobierania tweetów: {e}') await ctx.send(f'Wystąpił błąd podczas pobierania tweetów: {e}') @bot.event async def on_ready(): print(f'Zalogowano jako {bot.user.name} ({bot.user.id})') @bot.event async def on_command_error(ctx, error): if isinstance(error, commands.CommandInvokeError): print(f'Błąd podczas przetwarzania komendy: {error.original}') await ctx.send('Wystąpił błąd podczas przetwarzania komendy.') if isinstance(error, commands.CommandNotFound): await ctx.send('Nieprawidłowa komenda.') bot.run('...')
额外优化说明
- 使用列表推导式简化JSON文件路径的生成,减少重复代码。
- 修复
get_tweets中字符串换行的语法错误,用\n替代直接换行。 - 新的
send_embed_segments函数会自动拆分字段,确保每个Embed的总字符数不超过6000,同时保留原Embed的标题、颜色和描述。
内容的提问来源于stack exchange,提问作者Darklord
相关产品推荐
相关产品推荐

