☰
30秒用Python实现PDF转Word:TaoToken统一Key接入与PyInstaller打包实测
2026/10/7 19:54:06 网站建设 项目流程

1. 为什么我要自己写一个 PDF 转 Word 脚本

PDF 转 Word 这件事,看起来简单,真到用的时候处处是坑。WPS 的 PDF 转 Word 要开会员,在线转换网站要么限制页数,要么转完给你加一页广告水印,公司内部文档还不敢往陌生站点上传。我平时写技术文档、整理合同、处理论文,PDF 转 Word 是高频需求,与其每次求人开会员,不如自己写个脚本,双击就能用。

这个脚本的核心思路很直接:用 Python 读取 PDF 内容,调用大模型接口把内容整理成 Word 能识别的结构化文本,再用 python-docx 生成 .docx 文件。难点不在代码本身,而在接口调用——你得有一个稳定、便宜、不用折腾账号的 API 通道。我试过好几家,最后固定在 TaoToken 上,一个 Key 就能调通多个模型,不用来回换配置。

这篇文章我会带你走完整条链路:在 PyCharm 里配好 TaoToken 的统一 Key,写一个能跑的 PDF 转 Word 脚本,处理几个常见的报错,最后用 PyInstaller 打包成 exe,发给同事也能直接用。全程代码可复制,配置片段可照抄,30 秒跑通不是夸张说法——前提是你把环境准备好。

适合谁看?会一点 Python 基础、用过 PyCharm、想给自己或团队做个内部小工具的人。不需要你懂大模型原理,也不需要你研究 PDF 解析算法,跟着步骤走就行。

先说清楚一件事:PDF 转 Word 的准确率,取决于 PDF 本身的结构。纯文本 PDF 转出来效果最好,扫描件需要先 OCR,复杂排版的表格会有错位。这个脚本解决的是「快速拿到可编辑的 Word 初稿」,不是「像素级还原排版」。心态摆正,用起来会很舒服。

2. TaoToken 统一 Key 接入:PyCharm 里的前置配置

在写代码之前,先把 API 通道配好。TaoToken 的定位是统一 Key 接入多个模型,你不需要为每个模型单独注册账号、单独充值、单独记 Key。官网在 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,注册后在控制台生成一个 API Key,后面所有调用都用它。

PyCharm 这边要做两件事:一是装依赖,二是把 Key 和 Base URL 配到环境变量或配置文件里。我推荐用.env文件管理,方便切换,也避免把 Key 硬编码进代码提交到 Git。

先建项目。打开 PyCharm,新建一个 Pure Python 项目,解释器选 3.9 以上。然后在项目根目录建一个requirements.txt,内容如下:

openai>=1.30.0 pypdf>=4.2.0 python-docx>=1.1.0 python-dotenv>=1.0.1 pyinstaller>=6.6.0

在 PyCharm 底部的 Terminal 里执行:

pip install -r requirements.txt

装完之后,在项目根目录建一个.env文件,写入你的配置:

TAOTOKEN_API_KEY=sk-你的Key粘贴在这里 TAOTOKEN_BASE_URL=https://taotoken.net/api TAOTOKEN_MODEL=claude-3-5-sonnet-20241022

这里三个变量分别对应:Key、API 地址、模型 ID。Base URL 用https://taotoken.net/api,不要加多余的路径。模型 ID 按你控制台里可用的填,我常用 Claude 系列做文本整理,效果稳。

注意:.env文件不要提交到 Git。在项目根目录建.gitignore,加一行.env就行。

如果你习惯用 PyCharm 的 Run Configuration 配环境变量,也可以:Run → Edit Configurations → Environment variables,把上面三个键值对填进去。两种方式选一种,别重复配,否则排查起来容易乱。

Key 的获取路径:登录后进控制台,找到 API Keys 页面,新建一个 Key,复制出来。这个 Key 只在创建时完整显示一次,记得存好。如果你后面要做长期编码或 Agent 类任务,可以了解下 Coding Plan,按量或包月都有,比单次调用划算。

配置完成后,写个最小验证脚本check_key.py:

import os from dotenv import load_dotenv from openai import OpenAI load_dotenv() client = OpenAI( api_key=os.getenv("TAOTOKEN_API_KEY"), base_url=os.getenv("TAOTOKEN_BASE_URL"), ) resp = client.chat.completions.create( model=os.getenv("TAOTOKEN_MODEL"), messages=[{"role": "user", "content": "回复两个字:通了"}], ) print(resp.choices[0].message.content)

跑一下,输出「通了」就说明 Key 和通道都没问题。这一步别跳过,后面所有报错排查都以这个为基准。

3. 可复制配置:PDF 转 Word 脚本完整代码

配置通了,开始写主脚本。整个流程分四步:读 PDF 文本、调模型整理、生成 Word、保存文件。我把代码拆成函数,方便你改。

先建main.py:

import os import sys from dotenv import load_dotenv from openai import OpenAI from pypdf import PdfReader from docx import Document load_dotenv() client = OpenAI( api_key=os.getenv("TAOTOKEN_API_KEY"), base_url=os.getenv("TAOTOKEN_BASE_URL"), ) MODEL = os.getenv("TAOTOKEN_MODEL") def extract_pdf_text(pdf_path: str) -> str: reader = PdfReader(pdf_path) pages = [] for i, page in enumerate(reader.pages): text = page.extract_text() or "" pages.append(f"【第{i+1}页】\n{text}") return "\n\n".join(pages) def polish_to_word_text(raw_text: str) -> str: prompt = ( "下面是从 PDF 提取的原始文本,可能有断行、乱序、多余空格。" "请整理成结构清晰的正文,保留段落和标题层级," "不要添加原文没有的内容,直接输出整理后的文本。\n\n" f"{raw_text}" ) resp = client.chat.completions.create( model=MODEL, messages=[{"role": "user", "content": prompt}], temperature=0.2, ) return resp.choices[0].message.content def save_docx(text: str, out_path: str): doc = Document() for line in text.split("\n"): line = line.strip() if not line: continue if line.startswith("#"): doc.add_heading(line.lstrip("# ").strip(), level=1) else: doc.add_paragraph(line) doc.save(out_path) def convert(pdf_path: str): if not os.path.isfile(pdf_path): print(f"文件不存在:{pdf_path}") return print("正在读取 PDF...") raw = extract_pdf_text(pdf_path) print(f"提取到 {len(raw)} 个字符,正在调用模型整理...") polished = polish_to_word_text(raw) out_path = os.path.splitext(pdf_path)[0] + ".docx" save_docx(polished, out_path) print(f"转换完成:{out_path}") if __name__ == "__main__": if len(sys.argv) < 2: print("用法:python main.py 你的文件.pdf") sys.exit(1) convert(sys.argv[1])

几个关键点说明一下。extract_pdf_text用 pypdf 逐页提取,加页码标记是为了让模型知道内容边界,整理时不会把两页内容混在一起。polish_to_word_text里 temperature 设 0.2,降低随机性,保证输出稳定。save_docx简单处理了#开头的标题,其余按段落写入。

如果你想要图形界面,把入口改成 tkinter 文件选择框:

import tkinter as tk from tkinter import filedialog def pick_and_convert(): root = tk.Tk() root.withdraw() path = filedialog.askopenfilename(filetypes=[("PDF", "*.pdf")]) if path: convert(path) if __name__ == "__main__": pick_and_convert()

这样双击运行就弹选择框,不用敲命令行。打包 exe 时用这个入口更友好。

依赖清单再确认一遍:openai、pypdf、python-docx、python-dotenv、pyinstaller。缺哪个补哪个,版本别锁太死,用>=就行。

4. 验证请求:跑通第一个 PDF 转 Word

代码写完,拿一个真实 PDF 测。我准备了一份 8 页的技术文档,纯文本带小标题,没有复杂表格。在 PyCharm Terminal 里执行:

python main.py ./test.pdf

预期输出:

正在读取 PDF... 提取到 12480 个字符,正在调用模型整理... 转换完成:./test.docx

打开生成的 test.docx,检查三件事:段落是否完整、标题层级是否保留、有没有明显的内容丢失。我实测下来,纯文本 PDF 的还原度在 90% 以上,个别断行需要手动调,但整体可编辑,比重新打字快太多。

如果你想在代码里加个成功校验,可以在convert末尾加:

from docx import Document d = Document(out_path) print(f"生成段落数:{len(d.paragraphs)}")

段落数为 0 说明模型返回空或保存失败,需要排查。

再测一个带表格的 PDF。表格类内容模型整理时容易丢结构,建议在 prompt 里加一句「表格内容用 Markdown 表格输出」,然后在save_docx里识别|开头的行转成 Word 表格。这部分代码稍复杂,先保证纯文本跑通,再逐步加。

验证阶段还要确认一件事:Key 的额度是否够用。8 页文档大概消耗几千 token,具体看模型。在控制台能看到用量明细。如果只是偶尔用,按量付费足够;如果每天批量转,考虑 Coding Plan 更省心。

跑通之后,你可以把脚本改成批量模式,遍历一个文件夹里所有 PDF:

import glob for f in glob.glob("./docs/*.pdf"): convert(f)

这样一次处理一批,效率翻倍。

5. 常见报错排查:401、local proxy failed、reading choices

这一步是重点,我踩过的坑基本都在这。按报错类型对照排查。

401 Unauthorized。最常见,Key 不对或没读到。先确认.env里TAOTOKEN_API_KEY没有多余空格和引号。再确认load_dotenv()在OpenAI()之前执行。如果用了 PyCharm 的 Run Configuration 环境变量,检查有没有和.env冲突。还有一种情况:Key 复制时漏了尾部字符,重新生成一个再试。

local proxy failed / connection error。这类报错通常是网络层问题。先确认TAOTOKEN_BASE_URL写的是https://taotoken.net/api,没有多余斜杠或路径。再检查本机有没有设置奇怪的系统代理,如果有,在代码里显式指定:

import httpx client = OpenAI( api_key=os.getenv("TAOTOKEN_API_KEY"), base_url=os.getenv("TAOTOKEN_BASE_URL"), http_client=httpx.Client(timeout=60.0), )

超时设长一点,大文档整理需要时间,默认超时容易断。

reading 'choices' / KeyError: 'choices'。说明返回结构不对,通常是模型 ID 写错,或者接口返回了错误信息但代码直接取choices。加个防御:

data = resp.model_dump() if "choices" not in data: print("返回异常:", data) return "" return data["choices"][0]["message"]["content"]

这样能看到真实错误,而不是被 KeyError 掩盖。

OAuth / authentication 相关报错。如果你之前配过其他工具的认证信息,可能和当前环境冲突。检查系统环境变量里有没有残留的OPENAI_API_KEY之类,有的话清掉,或者在本项目里显式覆盖。

PyInstaller 打包后报错找不到模块。打包时加--hidden-import:

pyinstaller --onefile --hidden-import=openai --hidden-import=pypdf --hidden-import=docx main.py

打包后 exe 和.env放同一目录,否则读不到配置。或者把配置写进代码常量,但那样不灵活,不推荐。

排查顺序建议:先跑check_key.py确认通道通,再跑main.py确认逻辑通,最后打包确认分发通。一层层来,别跳步。

6. 打包分发与后续接入建议

脚本跑通后,用 PyInstaller 打包成 exe,同事拿到就能用,不用装 Python。命令:

pyinstaller --onefile --windowed --name PDF2Word main.py

--windowed去掉黑框,适合图形界面版本。打包完成后,exe 在dist/目录下。把 exe 和.env放一起,双击运行。

如果想让 exe 更独立,可以把配置写进一个config.json,用代码读取,避免.env被误删。但 Key 写在文件里有泄露风险,内部小工具问题不大,对外分发要谨慎。

后续想扩展,几个方向:加 OCR 处理扫描件、加批量队列、加转换进度条。接口层面,如果你要做更复杂的 Agent 任务,比如自动整理一批文档并生成摘要,可以看看 Coding Plan,按任务量选套餐更划算。模型对话页面也能直接测试不同模型对同一份 PDF 的整理效果,找到最适合你文档类型的那一个。

接入文档里有各语言的调用示例,遇到参数不确定的时候翻一下。API Keys 页面管理你的 Key,定期轮换更安全。

最后说个实用技巧:转换前先用 pypdf 检查 PDF 是否加密,加密的先解密再转,否则提取出来是空文本。加一行判断:

if reader.is_encrypted: reader.decrypt("")

空密码能解的就解,解不了的手动处理。这个坑我踩过,排查半天以为是接口问题,结果是 PDF 本身加密。

工具做出来是给自己省时间的,别追求一步到位。先跑通纯文本,再逐步加表格、加 OCR、加界面。每加一个功能测一次,稳扎稳打。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询