简介:这是一份面向IT从业者、数据工程师及Python初学者的轻量级文档自动化处理工具,专为解决批量Word文档(.doc/.docx)转纯文本(.txt)的重复性任务而设计,适用于文本预处理、日志归档、内容提取等场景。资源包共8个文件,含1个核心Python脚本(turnDocToTxt.py)、5个XML配置文件(支撑IDEA开发环境)、1个.iml模块定义文件及1个.gitignore,整体仅5KB,结构简洁,开箱即用。已有349人学习下载,体现了其在实际工作流中的实用价值。用户可直接运行主脚本实现目录递归扫描、段落文本提取、格式剥离与同名TXT输出,并内置基础错误处理逻辑;代码组织清晰,便于理解python-docx库的文档解析流程,也支持按需扩展日志记录或多线程优化,是掌握办公文档自动化处理的优质入门实践样本。
1. 项目缘起:为什么我们需要一个自己的Word转TXT工具?
你可能觉得,把Word文档转成TXT文本,这不是Word软件自带的“另存为”功能就能搞定的事吗?确实,对于偶尔处理一两个文档,手动操作一下没什么问题。但如果你像我一样,经常需要处理几十上百个文档,比如整理项目文档、批量处理用户上传的稿件、或者从一堆报告里提取纯文本进行分析,手动操作就成了一场噩梦。效率低下不说,还容易出错。更别提那些文档格式五花八门,有的嵌入了奇怪的样式,有的带着复杂的表格和图片,用Word自带的“另存为”功能,得到的TXT文件有时会多出很多莫名其妙的空格、换行符,甚至丢失部分内容。
这就是我动手写这个Python脚本的初衷。我需要一个能“无脑”批量处理、稳定可靠、并且完全可控的工具。市面上的在线转换工具,一来有文件大小和数量的限制,二来涉及到文档内容安全,把内部资料上传到第三方服务器总归不放心。自己动手,丰衣足食。用Python来实现,不仅轻量、免费,还能根据我的具体需求进行深度定制,比如只提取特定章节、过滤掉页眉页脚、或者统一转换后的编码格式。
这个工具的核心价值,就是自动化和可靠性。它解放了我们的双手,让我们能把精力放在更有价值的内容处理和分析上,而不是重复的格式转换劳动。接下来,我就把这个工具的源码和实现思路,毫无保留地分享给你。
2. 核心工具选型:为什么是python-docx而不是其他?
在Python生态里,处理Word文档(主要是.docx格式)的库有好几个,比如pywin32(调用本机Office COM组件)、docx2txt、textract,以及我们今天要用的python-docx。我最终选择了python-docx,这是经过一番考量和实际踩坑后得出的结论。
pywin32的优点是功能强大,能调用Word几乎所有的原生功能,转换效果理论上最完美。但它有个致命缺点:严重依赖Windows系统和本地安装的Microsoft Word。这意味着你的脚本无法在Linux服务器或无GUI的服务器上运行,也无法移植到其他没有安装Office的电脑上。这对于追求部署便捷性和跨平台能力的自动化脚本来说,是难以接受的。
docx2txt和textract这类库属于“一站式”解决方案,一个函数调用就能提取文本,非常方便。但“方便”的代价是可控性差。它们像是一个黑盒,你很难精细控制文本提取的逻辑。比如,当文档中有复杂的表格时,它们提取的文本格式可能很混乱;你无法方便地决定是否保留超链接文本、如何处理列表的缩进等。当遇到转换结果不符合预期时,调试和调整会非常困难。
python-docx则走了另一条路。它不是一个“转换器”,而是一个文档读写器。它允许你以编程的方式,像打开一个结构化的数据容器一样,打开一个.docx文件,然后遍历其中的段落(Paragraph)、表格(Table)、图片等元素,并读取每个元素的文本内容。这样做的好处显而易见:
- 完全可控:你可以精确地决定如何拼接每个段落的文本,比如段落之间加一个还是两个换行符。
- 跨平台:纯Python实现,不依赖任何外部Office组件,在任何能运行Python的环境下都能工作。
- 灵活扩展:因为你能访问文档的每一个部分,所以可以轻松地添加过滤逻辑(比如跳过标题、只提取特定样式的内容)、或者同时提取其他信息(比如读取表格数据并结构化保存)。
当然,python-docx主要针对.docx格式(Office 2007及以上)。对于古老的.doc格式,处理起来会麻烦一些,通常需要先通过其他方式(如LibreOffice的命令行)将其转换为.docx。在我们的批量场景下,可以预设输入为.docx,或者将.doc`` 的转换作为预处理步骤。为了聚焦核心,本文的脚本主要处理.docx`。
注意:
python-docx库的导入名是docx,但PyPI上的包名是python-docx。安装时需要使用pip install python-docx,但在代码中要import docx。
3. 环境准备与依赖安装
工欲善其事,必先利其器。在开始编码之前,我们需要搭建好Python环境并安装必要的库。这个过程很简单,但有几个细节需要注意,能避免后续很多莫名其妙的错误。
3.1 Python环境确认
首先,确保你的电脑上安装了Python。推荐使用Python 3.6及以上版本,因为它们有更好的库兼容性和语言特性。打开你的终端(Windows上是CMD或PowerShell,Mac/Linux上是Terminal),输入以下命令检查:
python --version # 或 python3 --version如果显示了类似Python 3.8.5的版本信息,说明环境OK。如果没有,你需要去Python官网下载并安装。安装时,请务必勾选“Add Python to PATH”这个选项,这能让你在终端中直接使用python命令。
3.2 安装核心库:python-docx
安装python-docx只需要一行命令。同样在终端中执行:
pip install python-docx如果你使用的是Python 3,并且系统里同时有Python 2,可能需要使用pip3:
pip3 install python-docx常见问题与解决:
- 权限错误:在Linux/macOS或Windows上,如果提示权限不足,可以在命令前加上
sudo(Linux/macOS)或以管理员身份运行终端(Windows)。更推荐的做法是使用虚拟环境。 - 下载慢或超时:因为网络原因,从默认的PyPI源下载可能会很慢。可以使用国内的镜像源来加速,例如清华源:
pip install python-docx -i https://pypi.tuna.tsinghua.edu.cn/simple - 安装成功但导入失败:极少数情况下,可能因为环境冲突导致。可以尝试先卸载再重新安装:
pip uninstall python-docx然后pip install python-docx。
安装成功后,可以打开Python交互界面简单测试一下:
import docx print(docx.__version__)如果没有报错并输出版本号,说明库已就绪。
3.3 (可选但推荐)使用虚拟环境
对于Python项目,我强烈建议使用虚拟环境(如venv或conda)。它能为每个项目创建独立的Python运行环境,避免不同项目间的库版本冲突。这是专业开发中的一个好习惯。
使用venv创建虚拟环境的步骤:
# 在你的项目目录下 python -m venv venv # 激活虚拟环境 # Windows (CMD/PowerShell): venv\Scripts\activate # Windows (Git Bash): source venv/Scripts/activate # Linux/macOS: source venv/bin/activate # 激活后,终端提示符前通常会显示 (venv) # 然后在虚拟环境中安装依赖 pip install python-docx当你完成工作后,可以输入deactivate来退出虚拟环境。
4. 脚本源码逐行解析与核心逻辑实现
下面就是整个批量转换工具的核心代码。我会将代码分成几个功能模块,并逐块进行详细解释,让你不仅知道怎么写,更明白为什么这么写。
4.1 模块导入与基础设置
import os import sys from pathlib import Path import docxos和sys:用于处理文件和目录路径、系统参数等。os模块是我们进行文件遍历和操作的基石。pathlib.Path:这是Python 3.4+引入的面向对象的路径操作库。相比传统的os.path,它的语法更清晰、更符合直觉。我们会用它来构建和检查路径。docx:这就是我们安装的python-docx库,核心功能都来自于它。
4.2 核心转换函数:convert_docx_to_txt
这是整个脚本的心脏,负责将单个.docx文件的内容提取并保存为.txt。
def convert_docx_to_txt(docx_path, txt_path=None, encoding='utf-8'): """ 将单个Word文档(.docx)转换为纯文本文件(.txt)。 参数: docx_path (str/Path): 源Word文档的路径。 txt_path (str/Path, 可选): 目标TXT文件的路径。如果为None,则在同一目录下生成同名文件。 encoding (str, 可选): 输出TXT文件的编码,默认为'utf-8'。推荐始终使用UTF-8以保证兼容性。 返回: bool: 转换成功返回True,失败返回False。 """ try: # 使用Path对象确保路径处理的一致性 docx_path = Path(docx_path) if not docx_path.is_file(): print(f"错误:文件不存在 - {docx_path}") return False # 如果未指定输出路径,则自动生成(同目录,同名,后缀改为.txt) if txt_path is None: txt_path = docx_path.with_suffix('.txt') else: txt_path = Path(txt_path) # 使用python-docx打开文档 doc = docx.Document(docx_path) # 用于累积所有文本内容 full_text = [] # 1. 遍历所有段落 (Paragraph) for para in doc.paragraphs: # 获取段落文本,并去除首尾空白字符 text = para.text.strip() if text: # 只添加非空段落 full_text.append(text) # 2. 遍历所有表格 (Table),将单元格内容按行拼接 for table in doc.tables: for row in table.rows: row_text = [] for cell in row.cells: # 获取单元格文本,同样去除首尾空白 cell_text = cell.text.strip() if cell_text: row_text.append(cell_text) # 将一行中所有单元格的文本用制表符(\t)连接,模拟表格结构 if row_text: full_text.append('\t'.join(row_text)) # 一个表格结束后,添加一个空行作为分隔,使输出更清晰 full_text.append('') # 将所有收集到的文本块用换行符连接起来 # 这里使用两个换行符(\n\n),让段落之间有空行,更符合阅读习惯。 output_content = '\n\n'.join(full_text) # 将内容写入TXT文件,使用指定的编码 # 使用 'w' 模式并指定 encoding,确保编码正确 with open(txt_path, 'w', encoding=encoding) as f: f.write(output_content) print(f"转换成功:{docx_path.name} -> {txt_path.name}") return True except Exception as e: # 捕获并打印任何异常,便于调试 print(f"转换失败:{docx_path}。错误信息:{e}") return False关键逻辑解析与设计选择:
- 异常处理 (
try...except): 文件操作和文档解析都可能出错(如文件损坏、权限不足、不支持的格式)。用try...except包裹核心逻辑,可以保证一个文件的转换失败不会导致整个程序崩溃,同时能打印出具体的错误信息,方便排查。 Path对象的运用:Path(docx_path).with_suffix(‘.txt’)这行代码非常优雅地解决了生成输出文件路径的问题。with_suffix方法会直接替换掉原路径的后缀名,无需手动拼接字符串,既安全又简洁。- 文本提取顺序:我们按照
先段落,后表格的顺序提取。这是因为在大多数文档中,段落是主体内容。表格可能穿插其中,但为了输出文本的线性顺序,我们将所有表格内容放在了所有段落内容之后。你也可以调整这个顺序,比如在遇到表格时,在其原本的位置插入标记,但这需要更复杂的文档结构分析。 - 空段落过滤:
if text:这行判断至关重要。Word文档中经常存在大量只有换行符或空格的“空段落”,直接提取会导致最终的TXT文件中充满无意义的空行。通过strip()和判断,我们只保留真正有内容的段落。 - 表格处理策略:对于表格,我们选择将其“扁平化”处理。遍历每一行 (
row),再将行中的每个单元格 (cell) 的文本提取出来,用制表符\t连接成一行字符串。这样,在TXT文件中,原本表格的每一行就变成了用制表符分隔的文本行,在一定程度上保留了表格的“列”信息,可以用文本编辑器或Excel的“分列”功能查看。每个表格处理完后,我们添加一个空字符串full_text.append(‘’),这样在最终输出时会产生一个空行,用以区分不同的表格。 - 段落分隔符:
‘\n\n’.join(full_text)使用两个换行符连接文本块。这使得每个段落(或表格行)在TXT中独立成段,段落间有空行,视觉效果更清晰,也符合许多文本处理工具的预期。 - 编码指定:
open(txt_path, ‘w’, encoding=‘utf-8’)明确指定编码为 UTF-8。这是现代文本处理的标准,可以完美支持中文、英文等所有字符,避免出现乱码。这是很多新手容易忽略但会导致严重问题的地方。
4.3 批量处理与目录遍历函数:batch_convert_docx_to_txt
单个文件转换是基础,批量处理才是生产力的体现。这个函数负责扫描一个目录,找到所有.docx文件,然后逐个调用上面的转换函数。
def batch_convert_docx_to_txt(input_dir, output_dir=None, recursive=False, encoding='utf-8'): """ 批量转换一个目录下的所有Word文档(.docx)为TXT文件。 参数: input_dir (str/Path): 包含源Word文档的目录路径。 output_dir (str/Path, 可选): 输出TXT文件的目录。如果为None,则输出到input_dir下的`txt_output`文件夹。 recursive (bool, 可选): 是否递归处理子目录。默认为False。 encoding (str, 可选): 输出文件的编码。 返回: tuple: (成功数量, 失败数量) """ input_dir = Path(input_dir) if not input_dir.is_dir(): print(f"错误:输入目录不存在 - {input_dir}") return 0, 0 # 设置输出目录 if output_dir is None: output_dir = input_dir / 'txt_output' else: output_dir = Path(output_dir) # 创建输出目录(如果不存在) output_dir.mkdir(parents=True, exist_ok=True) # 根据是否递归选择遍历方法 if recursive: # glob('**/*.docx') 会递归匹配所有子目录中的.docx文件 docx_files = list(input_dir.glob('**/*.docx')) else: # glob('*.docx') 只匹配当前目录下的.docx文件 docx_files = list(input_dir.glob('*.docx')) if not docx_files: print(f"在目录 {input_dir} 中未找到任何 .docx 文件。") return 0, 0 print(f"找到 {len(docx_files)} 个 .docx 文件,开始批量转换...") success_count = 0 fail_count = 0 for docx_file in docx_files: # 计算输出文件路径,保持原有目录结构(如果递归) if recursive: # 获取相对于输入目录的相对路径 relative_path = docx_file.relative_to(input_dir) # 将相对路径中的后缀改为.txt,并在输出目录下构建相同结构 txt_file = output_dir / relative_path.with_suffix('.txt') # 确保输出子目录存在 txt_file.parent.mkdir(parents=True, exist_ok=True) else: # 非递归模式,直接输出到output_dir根目录下 txt_file = output_dir / docx_file.with_suffix('.txt').name # 调用单个转换函数 if convert_docx_to_txt(docx_file, txt_file, encoding): success_count += 1 else: fail_count += 1 print(f"批量转换完成!成功:{success_count},失败:{fail_count}") return success_count, fail_count关键逻辑解析与设计选择:
- 输出目录管理:
output_dir.mkdir(parents=True, exist_ok=True)这行代码非常有用。parents=True意味着如果上级目录不存在,它会一并创建;exist_ok=True意味着如果目录已存在,它不会报错。这确保了无论输出目录是否存在,程序都能安全运行。 - 文件遍历:我们使用了
Path.glob()方法进行模式匹配。*.docx匹配当前目录,**/*.docx递归匹配所有子目录。glob返回的是一个生成器,我们将其转换为列表 (list()) 以便统计数量。 - 保持目录结构(递归模式):这是本脚本的一个亮点功能。当启用递归 (
recursive=True) 时,脚本会计算源文件相对于输入目录的相对路径 (relative_to),然后在输出目录下创建相同的子目录结构。这样,转换后的TXT文件就能和原来的Word文档保持一样的组织方式,对于管理大量分类文档极其重要。 - 进度反馈:在循环中,
convert_docx_to_txt函数会打印每个文件的转换状态。最后,函数会汇总成功和失败的数量,让用户对结果一目了然。
4.4 主程序入口与命令行交互
为了让脚本既可以被其他Python程序导入使用,也可以直接通过命令行运行,我们使用if __name__ == ‘__main__’:这个经典结构。
if __name__ == '__main__': # 简单的命令行参数解析(使用sys.argv) if len(sys.argv) < 2: # 如果没有提供参数,打印使用说明 print("用法: python word_to_txt.py <输入目录或文件> [输出目录] [--recursive] [--encoding ENCODING]") print("示例:") print(" python word_to_txt.py ./docs") print(" python word_to_txt.py ./docs ./output --recursive") print(" python word_to_txt.py ./docs ./output --encoding gbk") print(" python word_to_txt.py single_file.docx") # 单个文件转换 sys.exit(1) input_path = Path(sys.argv[1]) output_path = None recursive = False encoding = 'utf-8' # 解析可选参数(这是一个非常简单的解析器,对于复杂需求建议使用argparse库) i = 2 while i < len(sys.argv): arg = sys.argv[i] if arg == '--recursive': recursive = True i += 1 elif arg == '--encoding' and i + 1 < len(sys.argv): encoding = sys.argv[i + 1] i += 2 elif not arg.startswith('--') and output_path is None: # 第二个非`--`开头的参数视为输出目录 output_path = Path(arg) i += 1 else: i += 1 # 判断输入路径是文件还是目录 if input_path.is_file() and input_path.suffix.lower() == '.docx': # 单个文件转换模式 if output_path is None: output_path = input_path.with_suffix('.txt') success = convert_docx_to_txt(input_path, output_path, encoding) if not success: sys.exit(1) # 转换失败,返回非0退出码 elif input_path.is_dir(): # 批量目录转换模式 batch_convert_docx_to_txt(input_path, output_path, recursive, encoding) else: print(f"错误:输入路径既不是.docx文件也不是有效目录 - {input_path}") sys.exit(1)关键逻辑解析与设计选择:
- 双模式运行:脚本智能地判断第一个参数是文件还是目录。如果是单个
.docx文件,则调用convert_docx_to_txt;如果是一个目录,则调用batch_convert_docx_to_txt。这使得脚本的用途更加灵活。 - 简单的参数解析:这里实现了一个最基本的参数解析器。它识别
--recursive(递归)、--encoding(指定编码)等选项。对于更复杂的命令行工具,Python标准库中的argparse模块是更强大和专业的选择,但为了保持脚本的简洁和易于理解,这里使用了手动解析。你可以根据需要将其重构为使用argparse。 - 用户友好提示:当用户直接运行脚本而不带任何参数时,会打印出清晰的使用说明和示例,降低了使用门槛。
- 退出码:在单个文件转换失败时,使用
sys.exit(1)返回一个非零的退出码。这是一个好习惯,在将脚本集成到自动化流程(如Shell脚本、CI/CD流水线)中时,上游程序可以通过退出码判断任务是否成功。
5. 实战进阶:你可能遇到的坑与优化方案
把基础的脚本跑起来只是第一步。在实际生产环境中使用,你肯定会遇到各种边界情况和特殊需求。下面分享我踩过的一些坑以及对应的解决方案。
5.1 编码问题:乱码的根源与彻底解决
乱码是文本处理中最常见也最头疼的问题。其根源在于“编码不一致”:文件在保存时用一种编码(如GBK),而你在读取时用了另一种编码(如UTF-8)。
我们的脚本如何应对?
- 输出强制UTF-8:在
open()函数中明确指定encoding=‘utf-8’,确保我们生成的TXT文件是UTF-8编码。这是国际标准,兼容性最好。 - 输入编码的隐患:
python-docx库在读取.docx文件时,内部会处理编码问题,通常不需要我们操心。.docx本质上是一个ZIP压缩包,里面的XML文档默认就是UTF-8。但是,如果Word文档中的文本内容本身是从其他编码(如GB2312)的文本粘贴进来的,并且包含了该编码特有的字符,python-docx读取出来可能是正确的,因为Python 3的字符串是Unicode。问题通常出在后续环节。
更复杂的场景:处理其他来源的文本
如果你的脚本需要处理从其他渠道(如直接读取文本文件、从网络获取)得到的字符串,然后再与Word内容合并,就必须格外小心编码。
# 错误示范:不指定编码,依赖系统默认,极易出乱码 with open('other_source.txt', 'r') as f: external_text = f.read() # 正确做法:明确知道源文件的编码 try: with open('other_source.txt', 'r', encoding='gbk') as f: # 假设源文件是GBK编码 external_text = f.read() except UnicodeDecodeError: # 如果GBK解码失败,可以尝试其他常见编码,如utf-8, latin-1 with open('other_source.txt', 'r', encoding='utf-8', errors='ignore') as f: external_text = f.read() # 使用errors='ignore'忽略无法解码的字符最佳实践:在项目的开始,就统一所有文本文件的编码为UTF-8。如果必须处理混合编码的文件,可以尝试使用chardet库自动检测文件编码,但这并非100%准确。
5.2 格式丢失与样式信息提取
我们的脚本提取的是“纯文本”,这意味着所有字体、颜色、加粗、斜体、字号等样式信息,以及图片、图表、公式等非文本对象,都会丢失。这是由“纯文本(TXT)”的格式特性决定的。
如果你需要保留部分格式信息怎么办?
保留基础排版:我们已经做了一些工作,比如用空行分隔段落、用制表符分隔表格单元格。你还可以进一步:
- 识别标题:
python-docx的Paragraph对象有一个style.name属性。你可以判断如果para.style.name以‘Heading’开头,就在该段落文本前加上#(Markdown标题语法)或特定的标记。
for para in doc.paragraphs: text = para.text.strip() if text: if para.style.name and para.style.name.startswith('Heading'): full_text.append(f"# {text}") # Markdown格式 else: full_text.append(text)- 保留列表:检查段落样式或段落开头的字符,判断是否为列表项,然后为其添加
-或1.等前缀。
- 识别标题:
转换为富文本格式:如果纯文本无法满足需求,可以考虑转换为其他能保留样式的格式。
- Markdown:如上所示,可以将标题、加粗(
**文本**)、斜体(*文本*)等转换为Markdown语法。这需要更复杂地解析Run对象的属性(para.runs可以获取段落内具有不同样式的文本片段)。 - HTML:原理类似,用HTML标签包裹文本。
python-docx本身不直接支持转HTML,但有一些第三方库如mammoth专门做这件事,效果更好。 - PDF:如果需要精确保持版面,转换为PDF是更好的选择。但这通常需要借助其他库(如
reportlab)或外部工具(如LibreOffice的命令行soffice)。
- Markdown:如上所示,可以将标题、加粗(
核心取舍:在决定之前,一定要问自己最终用途是什么。如果是为了做全文搜索、自然语言处理,纯文本是最佳选择。如果是为了生成带简单排版的网页或文档,Markdown是很好的平衡点。如果需要原样打印或分发,PDF才是目标。
5.3 性能优化:处理超大型文档或海量文件
当处理一个几百页的Word文档,或者一个包含数万个文件的目录时,基础脚本可能会遇到内存或速度问题。
优化策略:
流式处理与分块写入:对于单个超大文档,我们目前是将所有文本累积在
full_text列表中,最后一次性写入文件。如果文档极大,这会消耗大量内存。可以改为边提取边写入:with open(txt_path, 'w', encoding=encoding) as f: for para in doc.paragraphs: text = para.text.strip() if text: f.write(text + '\n\n') # 立即写入文件 # ... 类似地处理表格这样做内存占用极小,但缺点是如果后续处理失败,文件可能处于不完整状态。
多进程/多线程加速(针对海量文件):批量转换时,每个文件的处理是独立的,这是“令人尴尬的并行”问题,非常适合用多进程来加速。Python的
concurrent.futures模块让这变得简单:from concurrent.futures import ProcessPoolExecutor, as_completed def batch_convert_parallel(input_dir, output_dir, recursive=False, max_workers=4): # ... [前面的目录准备和文件查找代码不变] ... with ProcessPoolExecutor(max_workers=max_workers) as executor: # 提交所有任务 future_to_file = {executor.submit(convert_docx_to_txt, docx_file, txt_file): docx_file for docx_file, txt_file in zip(docx_files, txt_files_list)} # 等待并获取结果 for future in as_completed(future_to_file): docx_file = future_to_file[future] try: success = future.result() if success: success_count += 1 else: fail_count += 1 except Exception as e: print(f"处理文件 {docx_file} 时发生未捕获异常: {e}") fail_count += 1注意:多进程适用于CPU密集型任务,且进程间通信有开销。如果转换任务本身很快(小文件),创建进程的开销可能抵消并行带来的收益。通常,在处理成千上万个文件时,效果显著。
max_workers设置为CPU核心数左右比较合适。进度显示:对于长时间运行的批量任务,给用户一个进度反馈非常重要。可以使用
tqdm这个库来轻松添加进度条。pip install tqdmfrom tqdm import tqdm # 在批量转换的循环处 for docx_file in tqdm(docx_files, desc="转换进度"): # ... 转换逻辑 ...
5.4 错误处理与日志记录
我们目前的脚本将错误信息打印到控制台。这对于手动运行足够了,但对于自动化任务,最好将日志记录到文件,以便事后排查。
简单的日志记录改进:
import logging # 在脚本开头配置日志 logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', handlers=[ logging.FileHandler('conversion.log', encoding='utf-8'), logging.StreamHandler() # 同时输出到控制台 ]) def convert_docx_to_txt(docx_path, txt_path=None, encoding='utf-8'): try: # ... [转换逻辑] ... logging.info(f"转换成功:{docx_path.name} -> {txt_path.name}") return True except Exception as e: logging.error(f"转换失败:{docx_path}。错误信息:{e}", exc_info=True) # exc_info=True会打印堆栈跟踪 return False这样,所有的成功和失败信息,连同时间戳和错误详情,都会同时显示在屏幕并保存到conversion.log文件中。
6. 完整脚本整合与使用示例
将上述所有代码块整合在一起,就是一个功能完整、健壮的批量Word转TXT工具。你可以将以下代码保存为一个文件,例如word_to_txt.py。
""" word_to_txt.py - 批量将Word文档(.docx)转换为纯文本文件(.txt) 作者:你的名字 描述:一个可靠、可配置的Python脚本,用于自动化处理Word到TXT的转换,支持单个文件、批量目录及递归处理。 """ import os import sys import logging from pathlib import Path import docx # 配置日志 logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', handlers=[ logging.FileHandler('word_to_txt_conversion.log', encoding='utf-8'), logging.StreamHandler() ]) def convert_docx_to_txt(docx_path, txt_path=None, encoding='utf-8'): """转换单个.docx文件为.txt文件。""" try: docx_path = Path(docx_path) if not docx_path.is_file(): logging.error(f"文件不存在 - {docx_path}") return False if txt_path is None: txt_path = docx_path.with_suffix('.txt') else: txt_path = Path(txt_path) doc = docx.Document(docx_path) full_text = [] # 提取段落 for para in doc.paragraphs: text = para.text.strip() if text: full_text.append(text) # 提取表格 for table in doc.tables: for row in table.rows: row_text = [] for cell in row.cells: cell_text = cell.text.strip() if cell_text: row_text.append(cell_text) if row_text: full_text.append('\t'.join(row_text)) full_text.append('') # 表格间空行 output_content = '\n\n'.join(full_text) with open(txt_path, 'w', encoding=encoding) as f: f.write(output_content) logging.info(f"转换成功:{docx_path.name} -> {txt_path.name}") return True except Exception as e: logging.error(f"转换失败:docx_path。错误信息:e", exc_info=True) return False def batch_convert_docx_to_txt(input_dir, output_dir=None, recursive=False, encoding='utf-8'): """批量转换目录下的所有.docx文件。""" input_dir = Path(input_dir) if not input_dir.is_dir(): logging.error(f"输入目录不存在 - {input_dir}") return 0, 0 if output_dir is None: output_dir = input_dir / 'txt_output' else: output_dir = Path(output_dir) output_dir.mkdir(parents=True, exist_ok=True) pattern = '**/*.docx' if recursive else '*.docx' docx_files = list(input_dir.glob(pattern)) if not docx_files: logging.warning(f"在目录 {input_dir} 中未找到任何 .docx 文件。") return 0, 0 logging.info(f"找到 {len(docx_files)} 个 .docx 文件,开始批量转换...") success_count = 0 fail_count = 0 for docx_file in docx_files: if recursive: relative_path = docx_file.relative_to(input_dir) txt_file = output_dir / relative_path.with_suffix('.txt') txt_file.parent.mkdir(parents=True, exist_ok=True) else: txt_file = output_dir / docx_file.with_suffix('.txt').name if convert_docx_to_txt(docx_file, txt_file, encoding): success_count += 1 else: fail_count += 1 logging.info(f"批量转换完成!成功:{success_count},失败:{fail_count}") return success_count, fail_count if __name__ == '__main__': if len(sys.argv) < 2: print("用法: python word_to_txt.py <输入目录或文件> [输出目录] [--recursive] [--encoding ENCODING]") print("示例:") print(" python word_to_txt.py ./docs") print(" python word_to_txt.py ./docs ./output --recursive") print(" python word_to_txt.py ./docs ./output --encoding gbk") print(" python word_to_txt.py single_file.docx") sys.exit(1) input_path = Path(sys.argv[1]) output_path = None recursive = False encoding = 'utf-8' i = 2 while i < len(sys.argv): arg = sys.argv[i] if arg == '--recursive': recursive = True i += 1 elif arg == '--encoding' and i + 1 < len(sys.argv): encoding = sys.argv[i + 1] i += 2 elif not arg.startswith('--') and output_path is None: output_path = Path(arg) i += 1 else: i += 1 if input_path.is_file() and input_path.suffix.lower() == '.docx': if output_path is None: output_path = input_path.with_suffix('.txt') success = convert_docx_to_txt(input_path, output_path, encoding) sys.exit(0 if success else 1) elif input_path.is_dir(): batch_convert_docx_to_txt(input_path, output_path, recursive, encoding) else: logging.error(f"输入路径无效 - {input_path}") sys.exit(1)使用示例:
转换单个文件:
python word_to_txt.py 我的报告.docx(会在同目录生成
我的报告.txt)转换整个目录(非递归):
python word_to_txt.py ./project_docs(会在
./project_docs/txt_output/下生成TXT文件)递归转换整个目录及其所有子目录:
python word_to_txt.py ./project_docs ./converted_texts --recursive(会在
./converted_texts/下保持原目录结构生成TXT文件)指定输出编码(如GBK):
python word_to_txt.py ./docs ./output --encoding gbk
这个脚本已经具备了生产环境使用的雏形。你可以根据自己的需求,轻松地修改或扩展它,比如添加更多格式处理规则、集成到Web服务中,或者作为一个模块导入到你更大的数据处理流程里。希望这份详细的解析和源码,能成为你自动化办公工具箱里的一件利器。
本文还有配套的精品资源,点击获取