You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Discord Bot开发:Pandas DataFrame读取谷歌表格数据遇KeyError报错及优化方案咨询

问题分析与解决方案

先帮你拆解下碰到的KeyError: 0问题,再给你几个更优的实现思路:

1. 核心错误原因

你代码里的问题主要有两个:

  • 命令参数错误:Discord.py的命令函数第一个参数必须是ctx(上下文对象),你写成了message,导致你把上下文对象当成用户ID去匹配表格数据,自然找不到对应行,最后取索引0就抛出了KeyError。
  • 多余的await关键字:Pandas的DataFrame操作是同步的,不需要加await,这属于误用异步语法。

2. 修复后的基础代码

先把核心问题修正,假设你表格里的Discord ID是字符串类型(如果是数字类型,把str(ctx.author.id)改成ctx.author.id即可):

import aiohttp
import discord
import asyncio
from discord.ext import commands
from oauth2client.service_account import ServiceAccountCredentials as SAC
import gspread
import pandas as pd

bot = commands.Bot(command_prefix='!')
# 补充Drive权限,避免部分访问受限问题
scope = ['https://spreadsheets.google.com/feeds', 'https://www.googleapis.com/auth/drive']
Json = 'xxx.json'
Connect = SAC.from_json_keyfile_name(Json, scope)
GoogleSheets = gspread.authorize(Connect)
sheet = GoogleSheets.open_by_key('your_spreadsheet_key')
Sheets = sheet.sheet1
# 初始加载表格数据
df = pd.DataFrame(Sheets.get_all_records())

@bot.event
async def on_ready():
    await bot.wait_until_ready()
    bot.session = aiohttp.ClientSession()
    print('Logged in as')
    print(bot.user.name)
    print(bot.user.id)
    print('------------')

@bot.command(name='LList')
async def llist(ctx, a: str):
    # 获取当前调用命令的用户ID,转换为表格中存储的类型
    user_id = str(ctx.author.id)
    # 筛选匹配的行
    matching_data = df[df['Discord ID'] == user_id]
    # 处理用户不存在的情况
    if matching_data.empty:
        await ctx.send("未找到你的票务信息!")
        return
    # 用iloc[0]替代直接[0],避免索引混乱问题
    ticket_count = matching_data['ticket\n(total)'].iloc[0]
    await ctx.send(f"```\n{a}\n You have {ticket_count} ticket```")

bot.run('your_bot_token')

3. 更优的实现方案

如果你的表格数据量大或需要实时更新,直接加载整个DataFrame到内存不是最优解,推荐以下几种思路:

方案一:按需查询,不加载全量数据

利用gspread的原生查询功能,直接在Google Sheets中定位目标行,减少本地数据处理:

@bot.command(name='LList')
async def llist(ctx, a: str):
    user_id = str(ctx.author.id)
    try:
        # 假设Discord ID在表格第1列,查找匹配单元格
        target_cell = Sheets.find(user_id, in_column=1)
        # 假设ticket列在第2列,获取对应值
        ticket_value = Sheets.cell(target_cell.row, 2).value
        await ctx.send(f"```\n{a}\n You have {ticket_value} ticket```")
    except gspread.exceptions.CellNotFound:
        await ctx.send("未找到你的票务信息!")

方案二:定时刷新缓存的DataFrame

如果需要频繁查询,定时刷新DataFrame缓存,避免每次请求都调用Google Sheets API:

async def refresh_data_cache():
    global df
    while True:
        # 每5分钟刷新一次数据
        df = pd.DataFrame(Sheets.get_all_records())
        await asyncio.sleep(300)

@bot.event
async def on_ready():
    await bot.wait_until_ready()
    bot.session = aiohttp.ClientSession()
    # 启动定时刷新任务
    bot.loop.create_task(refresh_data_cache())
    print('Logged in as')
    print(bot.user.name)
    print(bot.user.id)
    print('------------')

方案三:使用Google Sheets API直接查询

如果熟悉Google Sheets API,可以用spreadsheets.values.get配合查询参数,只拉取匹配的行数据,进一步减少传输量。

额外注意事项

  • 确保你的服务账号邮箱已被添加到目标表格的共享列表中,否则会出现权限错误。
  • 表格列名要和代码中的完全一致,比如ticket\n(total)带换行的列名,要保证DataFrame加载后列名匹配。
  • 注意用户ID的数据类型一致性,表格中存数字就用数字匹配,存字符串就用字符串匹配。

内容的提问来源于stack exchange,提问作者Mo Carson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 02:52:47