ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

MySQLdb 连库脚本:用走 TaoToken 的 Codex 对照 cursor 与 fetchall 改写

MySQLdb 连库脚本:用走 TaoToken 的 Codex 对照 cursor 与 fetchall 改写 MySQLdb 脚本连 nowasp、cursor 拿游标执行 select、fetchall 取回元组——这几行在 Python 2 的机器上跑得挺顺换到 Python 3最后那句print record[0]直接报错。要把它规范化先把执行工具接上TaoToken 的接法不复杂打开 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 注册账号、建一把 Key再把 Base URL 填 https://taotoken.net/api模型 ID 以模型广场当时的列表为准。通道通了之后把原始脚本整段贴给 Codex让它逐行对照cursor.execute里的 SQL 和fetchall返回的元组顺序先补上 try/except/finally 保证cursor.close()与db.close()一定执行再给出两版改法。这里有个边界要先说清楚Codex 只负责生成、解释、对照代码它不会连上你的 nowasp 库也不会替你执行execute。真正跑 SQL 的是你本机的 Python 解释器跑完把输出或报错贴回对话它接着改。数据库那一层始终握在你自己手里TaoToken 只出现在 Key 和模型通道这一层这是本文所有步骤的前提。1. 那段 nowasp 连库脚本问题不在八行本身1.1 八行代码各自在干什么原始脚本的结构很清晰MySQLdb.connect(hostlocalhost, userroot, passwd..., dbnowasp)建立连接db.cursor()拿一个游标对象cursor.execute(select * from accounts)把 SQL 送到服务端cursor.fetchall()把结果集一次性取回内存最后用一个 for 循环把每条记录的 0 到 3 号下标打印出来。在 Python 2 里这八行能出结果因为那时候print还是语句print record[0], record[1]这种写法合法。到了 Python 3print变成函数缺少括号就是SyntaxError: Missing parentheses in call to print脚本连第一行连接代码都跑不到就退出了。真正麻烦的不是这个语法错而是它掩盖了另外三个问题凭据明文写在源码里、游标和连接没有可靠的关闭路径、record[0]到record[3]这种下标取法完全依赖select *的列顺序。语法一改就跑但后三个问题会在换机器、加字段、并发跑的时候一起爆发。1.2 把原始写法拆成一张对照表规范化之前先看清楚每一行欠了什么。下面这张表不是让你背而是给 Codex 的提示词当素材——把表里的信息写进提示词它给出的改法会精准很多。原始写法埋下的问题规范化落点MySQLdb.connect(..., passwd..., dbnowasp)密码写死在源码进版本库就泄露挪到环境变量或本地配置文件源码里只留os.getenvdb.cursor()游标创建后没有关闭路径异常时泄漏try/finally或用contextlib.closingcursor.execute(select * from accounts)列顺序即索引顺序加字段就错位显式写列名或改成参数化查询for record in result: print record[0], ...Python 3 语法错且下标含义不直观改print(...)或直接元组解包没有 try/except连接失败时后续代码继续跑报错信息不好读捕获MySQLdb.Error打印可读信息表里最容易被忽略的是第三行。fetchall()返回的是元组的元组外层每个元素对应一行内层按 SELECT 的列顺序排列。你写record[0]的时候其实是在说第一列可代码里看不出第一列是 id 还是 account。等哪天有人给 accounts 表加了一个字段并放在最前面这四行打印全部错位而且不会报错——这是比语法错更难查的那种。2. 给 Codex 接上 TaoToken 通道config.toml 里只填 /api2.1 建 Key 这一步只在官网完成打开 TaoToken 注册账号进控制台创建一把 API Key复制出来先存好后文统一写成占位符YOUR_API_KEY。顺手在模型广场确认一下你要用的模型 ID别凭记忆填一个自己以为存在的名字——模型 ID 以 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 上的模型广场列表为准。有两个反直觉的点值得提前知道。第一Key 不要写进 Python 脚本也不要写进config.toml明文里用环境变量传。第二官网地址和接口地址是两个东西注册、建 Key、看模型广场、看用量用带参数的官网链接填进工具的 Base URL 只能是https://taotoken.net/api末尾不要补/v1更不要把官网首页地址填进去。2.2 ~/.codex/config.toml 里的 model_provider 与 base_urlCodex 的模型通道写在配置文件里Linux 和 macOS 是~/.codex/config.tomlWindows 是%USERPROFILE%\.codex\config.toml。如果你之前已经在用别的供应商不要删掉原来的段新增一个 provider 段即可切换时改model_provider一行。# ~/.codex/config.toml model YOUR_MODEL_ID model_provider taotoken [model_providers.taotoken] name TaoToken base_url https://taotoken.net/api env_key TAOTOKEN_API_KEY wire_api chatbase_url就写到/api为止多一个字符都可能让请求打到不存在的路径上。env_key这一行告诉 Codex 去哪里读密钥所以还要在终端里把它设上# Linux / macOS写进 ~/.bashrc 或 ~/.zshrc 后重新开一个终端 export TAOTOKEN_API_KEYYOUR_API_KEY# Windows PowerShell setx TAOTOKEN_API_KEY YOUR_API_KEYwire_api的值跟着模型广场的说明走走 chat 协议的模型填chat如果该模型标注的是 responses 协议就改成responses。这一点不用猜模型广场页面会写。2.3 怎么确认通道真的通了配置写完先别急着改数据库脚本花一分钟验证通道。在任意一个项目目录下启动 Codex发一句和数据库无关的话比如用一句话说明 cursor.fetchall() 返回的数据结构。能正常回话说明 Key、base_url、模型 ID 三件事至少对上了可以进入下一步。如果这里就不通先解决通道问题再去改代码否则你会分不清是配置错还是 Python 错——同时排查两个变量是最浪费时间的做法。3. 把脚本整段贴给 Codex让它对齐 cursor.execute 与 fetchall3.1 提示词要写清只做对照和改写很多人贴代码过去只写一句帮我改一下结果拿回来的是一份风格完全不同、还引入了新依赖的重写版。要让 Codex 逐行对照提示词里得把它限制住。下面这段可以直接改一改就用下面是一段最小可用的 Python 连库脚本Python 2 语法连的是我本机的 localhost / nowasp 库。 要求 1. 先逐行标注每行在做什么特别说明 cursor.execute 里的 SQL 与 cursor.fetchall() 返回的元组顺序之间的对应关系。 2. 不要连接任何数据库也不要执行任何 SQL只生成和解释代码。 3. 给出两版改法 A 版继续用 MySQLdb只修 print 语法和异常处理风格尽量贴近原文 B 版把连接参数拆成配置项用参数化查询并保证游标和连接一定关闭。 4. 两版都要保留 for 循环逐条输出的行为不要改成返回 DataFrame。 脚本如下 把原始八行粘贴在这里第 2 条必须写。不写清楚有些模型会自作主张给你一段顺手连一下验证的代码那是你不想要也不需要的。3.2 让它先标注 record[0] 到 record[3] 对应哪几列要让 Codex 说清record[0]到record[3]的含义得先给它表结构否则它只能根据列名猜。在你本机的 MySQL 客户端里执行一句SHOW COLUMNS FROM accounts;把返回的字段名和顺序贴进对话再补一句select *的列顺序就是上面这个顺序请据此说明record[0]到record[3]分别是什么。这样它给出的 B 版就能写成显式列名而不是继续猜。这里也要重复一次边界SHOW COLUMNS是你在本地客户端执行的Codex 不参与执行它只是读你贴过去的结果。3.3 try/except/finally 的位置比异常类型更重要让 Codex 加异常处理的常见结果是它给MySQLdb.connect包了 try却没管cursor或者把db.close()写在 try 的最后一行——一旦中间抛异常这行永远不会执行连接就被挂在那里。正确的结构是三层连接和游标在 try 之前先初始化为Nonetry 里只放真正会出错的操作except 里捕获MySQLdb.Error并打印finally 里判断非None再关闭且游标的close()要排在连接的close()前面。在提示词里直接点明这个顺序能省掉一轮返工。4. 两版改法MySQLdb 最小修复版与配置项 参数化查询版4.1 A 版继续用 MySQLdb只修 print 与异常A 版的目标是让这段脚本今天就能跑起来改动范围压到最小不引入新依赖也不改文件结构。#!/usr/bin/env python # -*- coding: utf-8 -*- import MySQLdb db None cursor None try: db MySQLdb.connect( hostlocalhost, userroot, passwdYOUR_DB_PASSWORD, dbnowasp, charsetutf8mb4, ) cursor db.cursor() cursor.execute(select * from accounts) result cursor.fetchall() for record in result: print(record[0], record[1], record[2], record[3]) except MySQLdb.Error as e: print(查询失败:, e) finally: if cursor is not None: cursor.close() if db is not None: db.close()改动集中在四处print加括号连接和游标提前初始化为None整段操作进 try关闭动作进 finally 并且先游标后连接。SQL 一个字没动select *也保留着因为它这一版的任务只是先能跑。4.2 B 版配置项 参数化查询 closingB 版解决的是下次还要改的问题。连接参数从源码里挪出去游标和连接交给contextlib.closing托管查询条件用参数化传递。#!/usr/bin/env python # -*- coding: utf-8 -*- import os from contextlib import closing import MySQLdb DB_CONFIG { host: os.getenv(NOWASP_HOST, localhost), user: os.getenv(NOWASP_USER, root), passwd: os.getenv(NOWASP_PASSWORD, ), db: os.getenv(NOWASP_DB, nowasp), charset: utf8mb4, } # 列名以你本地 SHOW COLUMNS FROM accounts 的结果为准 SQL select id, account, name, status from accounts where status %s def fetch_accounts(statusactive): with closing(MySQLdb.connect(**DB_CONFIG)) as db: with closing(db.cursor()) as cursor: cursor.execute(SQL, (status,)) return cursor.fetchall() def main(): try: rows fetch_accounts() except MySQLdb.Error as e: print(查询失败:, e) return for account_id, account, name, status in rows: print(account_id, account, name, status) if __name__ __main__: main()密码从NOWASP_PASSWORD环境变量读源码里只留键名。select *换成了显式列名for循环改成元组解包record[0]这种下标彻底消失。closing()保证无论正常返回还是中途抛异常游标和连接都会被关掉——它比 finally 更省心的地方是你不用再关心关闭顺序。需要注意的是B 版只做查询不涉及写操作。如果后面要加 INSERT/UPDATEclosing()不会替你 commit得在with块内显式调用db.commit()这一点可以在对话里继续追问 Codex让它给你补一段。4.3 两版怎么选看你要解决的是哪个问题对比项A 版B 版改动范围只动 print 和异常结构连接、SQL、循环全部重排依赖仍然只用 MySQLdb仍然只用 MySQLdb加标准库凭据位置仍在源码里挪到环境变量列顺序依赖仍靠select *显式列名 元组解包适合场景老脚本临时救急、要跑一次后面还要维护、要进版本库实践里的顺序通常是先落 A 版确认逻辑没跑偏隔一两天再落 B 版。两版并存不冲突A 版可以留在本地当对照。5. 本地跑通再回传报错print record[0] 之外的几个高频坑5.1 两版都在本机跑一遍A 版和 B 版都存成.py文件在终端里执行观察输出是不是四列值。B 版跑之前记得把环境变量设好export NOWASP_HOSTlocalhost export NOWASP_USERroot export NOWASP_PASSWORDYOUR_DB_PASSWORD export NOWASP_DBnowasp python check_accounts.pyA 版要跑得先把本地 MySQL 的 root 密码替换掉YOUR_DB_PASSWORD。这一步没人能替你做因为数据库在你的机器上。5.2 五个报错各自对应哪一行改完之后最常见的几个报错基本都能一眼定位SyntaxError: Missing parentheses in call to print还在用 Python 2 的 print 语句看 for 循环那一行。ImportError: No module named MySQLdbMySQLdb 对应的安装包是 mysqlclient本机可能没装或者缺少 MySQL 的开发头文件实在装不上把import MySQLdb换成import pymysql as MySQLdb也能先跑但异常类型要跟着换成pymysql.Error。OperationalError: (1045, Access denied for user rootlocalhost)账号密码不对检查环境变量有没有真的生效。OperationalError: (1049, Unknown database nowasp)库名写错或者连到了另一台 MySQL 实例。中文显示成问号或乱码连接参数里补charsetutf8mb4A 版和 B 版都已经加上了。Codex 那边如果连不上先看两件事Key 有没有正确写进TAOTOKEN_API_KEYbase_url是不是严格写成https://taotoken.net/api。写成官网首页地址、或者手滑在后面补了/v1都会直接失败。5.3 把输出和报错贴回去让它接着改这一步才是 Codex 真正省时间的地方。把完整的 traceback 连同脚本一起贴回去问一句这个报错落在第几行两版分别怎么改比只贴报错最后一行有效得多。它能看到你的环境变量名、SQL 写法、游标关闭顺序给出的修改建议才有针对性。如果错误来自数据库本身比如权限、库不存在那部分是你在 MySQL 客户端里排查完、改了连接参数之后再回到 Codex。工具链分工清楚来回折腾的次数会少很多。6. 改完这个脚本顺手把通道和 Key 对上6.1 用同一把 Key 在模型对话里试一次脚本改完、Codex 通道也通了可以用同一把YOUR_API_KEY去 TaoToken 模型对话 发一条测试消息比如让它解释fetchall()和fetchone()的区别。这一步有两个作用确认这把 Key 在网页侧也能用顺便看看刚才那些请求有没有记到账上。如果打算长期让 Codex 跟着改脚本可以到 Coding Plan 看一眼套餐够不够用要再建一把给别的项目用在 控制台 API Keys 里创建即可。6.2 三个入口按需打开通道配好之后日常会用到三个页面建 Key 和查用量去 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 调试提示词去模型对话如果后面想把这套通道迁到别的命令行工具上环境变量的字段名和写法可以参考 Claude Code 接入文档 里面的ANTHROPIC_BASE_URL、ANTHROPIC_AUTH_TOKEN、ANTHROPIC_MODEL三个变量和本篇 Codex 的base_url、env_key、model是一一对应的思路——Base URL 都填https://taotoken.net/api末尾不加/v1。最后留一句提醒select *改成显式列名这件事别一次改完所有脚本。挑一个天天要跑的跑稳一周再动下一个。数据库脚本的坑大多不是语法错而是看起来跑通了、结果列却悄悄换了位置慢一点反而更快。
返回列表