查看: 132|回复: 3

Python脚本用PyPDF2与gTTS实现PDF转有声读物的多页覆盖

[复制链接]
发表于 1 小时前 | 显示全部楼层 |阅读模式
原文要解决的问题是用 Python 把 PDF 文本抽取出来,再交给 gTTS 合成 mp3。脚本由两条链路组成:PyPDF2 负责按页读取和提取文本,gTTS 负责语音合成。原文环境为 Python 3.x,依赖 PyPDF2 与 gtts。

核心函数拆解:read_pdf(file_path) 以 rb 模式打开 PDF,用 PyPDF2.PdfFileReader 创建阅读器,通过 numPages 遍历页,调用 getPage(page_num).extractText() 收集每页文本,返回文本列表。convert_to_speech(text) 用 gTTS(text=text, lang='zh') 生成中文语音,并保存为 output.mp3。main() 从 input 获取 PDF 路径,先执行 read_pdf,再对每页调用 convert_to_speech。

原文基础实现整理如下:
  1. import PyPDF2
  2. from gtts import gTTS
  3. def read_pdf(file_path):
  4.     with open(file_path, 'rb') as file:
  5.         pdf_reader = PyPDF2.PdfFileReader(file)
  6.         text_content = []
  7.         for page_num in range(pdf_reader.numPages):
  8.             text_content.append(pdf_reader.getPage(page_num).extractText())
  9.         return text_content
  10. def convert_to_speech(text):
  11.     tts = gTTS(text=text, lang='zh')
  12.     tts.save('output.mp3')
  13.     print('有声读物已生成,请查看输出文件。')
  14. def main():
  15.     file_path = input('请输入 Pdf 文件路径:')
  16.     text_content = read_pdf(file_path)
  17.     for page_text in text_content:
  18.         convert_to_speech(page_text)
  19. if __name__ == '__main__':
  20.     main()
复制代码

参数与调用关系方面,lang 控制合成语言,原文固定为 zh;进阶版本的 convert_to_speech(text, lang, tts_speed) 将 tts_speed 传给 gTTS 的 slow 参数,但 slow 是慢速开关,不是任意速度数值。convert_multiple_pages_to_speech(file_path, pages, lang, tts_speed) 通过 pages 选择页面,再用 text_content[page_num] 取文本。pages 的索引语义原文没有说明,代码直接按列表下标使用;若传入自然页码,需要减 1,否则会错页或越界。

主要问题与排查重点:
1)输出覆盖。main 和多页函数都逐页调用 convert_to_speech,而函数内部固定保存为 output.mp3,后一页会覆盖前一页,最终只留下最后一页。排查时先看输出目录是否只有一个 output.mp3。修正方向是输出文件名带页码,或将多页文本合并后一次合成。
2)PyPDF2 接口兼容性。原文代码使用 PdfFileReader、numPages、getPage、extractText 这套接口;运行环境安装的 PyPDF2 版本若接口名不同,会出现找不到属性。应先核对所安装 PyPDF2 的版本和接口,再决定固定依赖或按实际接口改写读取部分。
3)slow 参数语义。tts_speed 变量名像速度,但 gTTS 的 slow 是布尔型慢速开关,传非布尔值不符合参数含义。
4)文本提取结果。extractText 按页提取,若 PDF 没有可提取的文本层,结果可能为空;原文未涉及 OCR 处理。

排查流程可参考:确认 Python 3.x;确认 PyPDF2 和 gtts 已安装;用明确路径确认 PDF 可读;打印 read_pdf 返回的页数和每页文本长度;检查 output.mp3 是否被覆盖;检查 pages 是否按 0 基索引传入;检查 lang 与 slow 参数是否符合 gTTS 调用含义。

按原文函数结构做小幅修正时,可保留 read_pdf 和 convert_to_speech 的职责,只把输出文件名加入页码、把 slow 改为布尔参数、在多页函数中传递页码,从而避免覆盖和参数误用。示例仍使用原文的 PyPDF2 旧接口;若运行环境接口不同,需要按实际版本调整读取部分:
  1. import PyPDF2
  2. from gtts import gTTS
  3. def read_pdf(file_path):
  4.     with open(file_path, 'rb') as file:
  5.         pdf_reader = PyPDF2.PdfFileReader(file)
  6.         text_content = []
  7.         for page_num in range(pdf_reader.numPages):
  8.             text_content.append(pdf_reader.getPage(page_num).extractText())
  9.         return text_content
  10. def convert_to_speech(text, page_num=0, lang='zh', slow=False):
  11.     tts = gTTS(text=text, lang=lang, slow=slow)
  12.     filename = 'output_%d.mp3' % page_num
  13.     tts.save(filename)
  14.     print('有声读物已生成:', filename)
  15. def convert_multiple_pages_to_speech(file_path, pages, lang='zh', slow=False):
  16.     text_content = read_pdf(file_path)
  17.     for page_num in pages:
  18.         convert_to_speech(text_content[page_num], page_num, lang, slow)
  19. def main():
  20.     file_path = input('请输入 Pdf 文件路径:')
  21.     text_content = read_pdf(file_path)
  22.     for page_num, page_text in enumerate(text_content):
  23.         convert_to_speech(page_text, page_num)
  24. if __name__ == '__main__':
  25.     main()
复制代码

适用场景是文本型 PDF 的有声化、按页选择合成和中文朗读。原文只覆盖文本提取与 gTTS 合成,没有实现扫描件 OCR、音频合并和断句优化,这些不应被当作原文已具备的能力。
回复

使用道具 举报

发表于 1 小时前 | 显示全部楼层

Re: Python脚本用PyPDF2与gTTS实现PDF转有声读物的多页覆盖

这篇整理很实用,尤其是把“输出覆盖”放在第一个排查点很关键。固定保存成 output.mp3 确实会让逐页合成只留下最后一页,改成按页码命名或者先把多页文本合并再一次性合成,都是合理方向。PyPDF2 旧接口兼容性和 slow 参数语义也提醒得很到位,很多人容易把 slow 当成任意速度值。多页函数里 pages 的 0 基索引问题也值得强调,最好在调用前明确自然页码和列表下标的转换,避免错页或越界。另外文本提取为空的情况可以再细一点,比如先打印每页文本长度,空页跳过或提示可能是扫描版 PDF。最后示例里的 main 函数好像没贴完整,补全后会更方便直接参考。
回复 支持 反对

使用道具 举报

发表于 1 小时前 | 显示全部楼层

Re: Python脚本用PyPDF2与gTTS实现PDF转有声读物的多页覆盖

楼主这篇整理挺清楚的,把 PyPDF2 抽文本和 gTTS 合成两条链路分开讲,排查点也列得比较实用。最关键的确实是输出覆盖问题:逐页调用却固定保存成 output.mp3,最后只会留下最后一页,改成带页码的文件名或先合并文本再一次合成都能解决。 另外几个提醒也很到位:pages 如果是自然页码要减 1,slow 只是布尔慢速开关不是任意速度,旧版 PyPDF2 接口在不同环境下可能不兼容。实际跑的时候建议先打印每页文本长度,确认 PDF 有可提取文本层;如果没有文本层,extractText 结果可能为空,这种情况就需要考虑 OCR 了。整体思路很适合做小工具原型,按楼主说的小幅修正保留原函数职责也很稳妥。
回复 支持 反对

使用道具 举报

发表于 1 小时前 | 显示全部楼层

Re: Python脚本用PyPDF2与gTTS实现PDF转有声读物的多页覆盖

楼主把两条链路和几个坑都拆得挺清楚,输出覆盖和多页索引这两个确实是实际跑的时候最先撞上的。页数一多,全都存成 output.mp3 的话,最后一页静悄悄把前面全盖掉,排查起来还以为是 gTTS 没出声。 我自己用的时候有几个小补充,跟楼主提到的方向一致: 一是 PyPDF2 那套旧接口现在确实不稳,较新的版本已经改成 PdfReader 加 len(reader.pages)、reader.pages.extract_text(),如果按原文代码直接跑报 AttributeError,先别怀疑文件,看下装的是哪个版本最省事。要么钉死依赖版本,要么按新接口改读取那几行。 二是 pages 用 0 基下标这个,建议在 convert_multiple_pages_to_speech 里加个范围检查,或者干脆在入口处把用户输入的自然页码统一减一,然后打一行“第几页到第几页”的日志。不然错页了很难发现,因为文件名对得上、内容却串了。 三是每页单独合成 mp3 后,最好把文件名带上页码范围或时间戳,比如 output_p3_20250101.mp3 这种,避免多次运行互相覆盖,也方便后面对照原文听。 四是提取出来的页文本可能是空字符串,比如扫描版没文本层或者页眉页脚页,gTTS 对空文本会直接抛错,所以循环里加个 if not text.strip(): continue 比较稳。真遇到整本
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-11-13 04:49 , Processed in 0.024739 second(s), 18 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部