先说个真实感受PDF 转 TXT 这件事难的不是“找到一个工具”而是“找到一个对的文件出来的结果能看”。我这些年整理资料库、做文本挖掘、给同事批量处理文档手上过的 PDF 少说也有几万个同一个文件换不同工具转结果能差出十万八千里——有的满屏乱码有的段落被拆得七零八落有的干脆给你一张白纸还有的把页眉页脚和正文搅在一起读起来像天书。所以这篇不讲虚的直接把我实际在用的六套方案摊开办公套件直接导出、在线转换站点、桌面 PDF 编辑器的批量导出、命令行工具、Python 脚本流水线、扫描件 OCR 流水线每一种都会说清楚它适合什么文件、关键参数怎么调、哪里最容易翻车。不管你是偶尔转一两份合同的学生还是每天要处理几百份报表的运营看完都能直接挑一条路走。前置提醒一句PDF 转 TXT 的成败八成在你打开文件之前就决定了先判断文件类型再谈工具。1. 动手前先分诊你的 PDF 到底是哪一类1.1 有文本层和纯图像完全是两码事很多人以为 PDF 就是一种“文档格式”其实它更像一个“打印结果的容器”。同一个 PDF可能里面规规矩矩存着每个字符的编码、字体、坐标也可能只是一张张拍好的照片贴上去。前者叫有文本层工具读的是字符后者叫扫描件或图片型 PDF工具看到的只有像素点你让它转文字它只能干瞪眼或者吐出一堆空白。这个区别决定了后面所有方案的分岔路。有文本层的文件任何一款转换工具基本都能出活差别只在于排版保留得好不好、断行处理得干不干净。纯图像的文件必须先过 OCR光学字符识别这一关把像素认成字才谈得上转 TXT。我见过太多人拿着扫描件去试七八个在线转换站全失败了然后骂工具垃圾——其实工具没毛病是路走错了。所以第一步永远是分诊不是选工具。还有一种中间态叫“伪文本层”PDF 里确实有文本对象但字体没有嵌入或者字符映射表ToUnicode缺失工具读出来的是一串谁也看不懂的符号。这种文件用普通方式转出来的就是乱码看起来像加密其实只是缺了字典。判断方法很简单后面会讲。1.2 三分钟自检法要不要上 OCR不用装任何软件三步就能判断。第一步用鼠标在 PDF 正文上拖一下。能选中、能高亮出蓝色底色说明有文本层怎么拖都是整块或者干脆选不中基本就是图片。第二步复制一小段粘贴到记事本里。粘出来是正常文字走文本层路线粘出来是空白或者乱码那就得看第三步。第三步把页面放大到 400% 以上看边缘。文字边缘有锯齿、有噪点、有轻微的倾斜或者纸张纹理那是扫描件放大后依然锐利干净那是电子排版即便复制出来乱码也大概率只是字体编码问题可以尝试换工具或换参数救回来不一定非得上 OCR。这三步做完你心里就有数了。我一般还会顺手看一眼文件体积纯文字的 PDF 通常几百 KB 到两三 MB扫描件因为存的是图片动辄十几 MB 甚至上百 MB页数一样的情况下体积差十倍以上基本可以确定是图像型。注意有些 PDF 是“混合型”前几页是电子排版后面附了扫描的签字页或附件。这种文件不要一刀切用脚本按页判断、分而治之比整本丢进 OCR 效果好得多也快得多。1.3 六种方案横向对比与选型建议先把全局摊开后面再逐个拆。下面这张表是我自己选型时用的判断依据你可以直接对照。方案适合的文件上手难度批量能力排版保留主要短板办公套件导出少量、结构简单的电子版极低弱一般复杂版式容易乱序在线转换站点临时几页、不敏感内容极低弱中等文件外传、页数限制桌面 PDF 编辑器中等批量、需保留结构低强较好需付费、体积大命令行工具大批量、服务器环境中极强好参数需记忆Python 脚本定制化、需清洗后处理中高极强可控要写代码OCR 流水线扫描件、图片型 PDF高强依赖预处理耗时、需调参选型逻辑其实很简单文件少、要求低走前两条文件多、要求稳走中间两条文件脏、要定制走后两条文件是扫描件只有最后一条路。我个人的默认路径是这样的先拿命令行工具跑一遍看看出来多少字、有没有乱码如果字数明显偏少说明文本层有问题或者根本是扫描件再切到 OCR 流水线如果字数正常但排版乱再考虑用脚本做后处理清洗。这个“先试探、再决定”的顺序比一上来就上重型方案省时间得多。2. 方案一办公套件直接另存最省事的路径2.1 打开方式决定了能不能成功大多数人的第一反应是用办公软件打开 PDF然后另存为文本。这条路能走通但有个前提你得让软件真的“解析”这个 PDF而不是把它当图片预览。常见的误区是直接把 PDF 文件拖进窗口有些套件会默认用“阅读模式”打开这时候你看到的虽然清楚但导出功能是灰的。正确做法是通过“打开文件”菜单明确选择 PDF 类型让软件进入编辑或转换流程。第一次打开时通常会弹出一个转换提示问你要不要把它转成可编辑文档这一步别跳过跳过之后导出的可能还是原样。转换过程本质上是软件在后台做一次版式识别把文字块、段落、表格重新组织成它自己的文档模型然后再由你另存。我实测下来这类方案对“单栏、纯文字、字号统一”的文件成功率很高几乎不用二次修改。但只要文件里有多栏排版、跨页表格、复杂的文本框叠加导出的顺序就容易乱本来左右两栏的内容会被按行拼在一起读起来像两句话被腰斩后强行缝合。遇到这种别硬扛换方案。还有一个细节值得注意转换时的语言设置。如果文件里有大量专业符号或者非中文内容把识别语言设成对应的语种成功率会明显提升。默认设置有时候会把特殊字符认错尤其是上下标、希腊字母、数学符号转出来变形的概率不低。2.2 导出纯文本时的参数与坑转成可编辑文档之后另存为纯文本这一步也有讲究。多数办公套件在“另存为”里提供纯文本选项点进去通常还能选编码。这里请务必选 UTF-8别用系统默认。我踩过这个坑一次批量处理两百多份资料全部用了默认编码结果在有特殊符号的页面里一部分字符变成了问号而且是在保存那一刻就丢了源文件没问题纯粹是编码不兼容。编码选错的表现很有辨识度中文正常但引号、破折号、省略号变成乱码或者生僻字变方块。UTF-8 能覆盖绝大多数情况如果目标系统明确要求别的编码再单独处理。另外两个小开关值得留意。一个是“保留换行符”勾上之后段落内的软换行会保留下来好处是排版信息还在坏处是每行末尾都会断开后续要合并不勾的话有些软件会把整段压成一行读起来反而不方便。我的建议是保留换行后续用脚本统一清洗可控性更高。另一个是“插入分页符”如果只是取文字可以关掉省得后面还要清理一堆换页标记。提示导出之后先别急着批量处理抽三页跟原文对照读一遍。重点看三处——段落开头有没有被吞字、数字和单位之间有没有多出空格、表格内容有没有串行。这三处没问题剩下的基本都是小毛病。3. 方案二在线转换站点快但要知道边界3.1 什么场景适合用什么场景绝对别用在线站点的优势只有一个字快。打开浏览器拖进去选输出格式下载全程不超过一分钟不用装任何东西手机也能操作。对于临时要看一份公开资料、转两页会议纪要这种需求它确实是最优解。但边界必须划清楚。第一内容敏感的文件不要上传。合同、身份材料、内部报表、未公开的研究数据一旦上传文件就离开了你的控制范围后续怎么存储、存多久、有没有被用于其他用途你都无法掌握。这不是危言耸听是基本的风险意识。第二页数多的文件不要用。多数站点对免费用户有页数或体积限制超了就排队、压缩或者直接拒绝转出来的结果还可能是分段的。第三格式复杂的文件不要指望它。在线站点为了兼容性通常用比较通用的解析逻辑遇到多栏、表格、公式效果往往不如本地工具。我的实际用法是只把完全公开、无所谓的短文档丢进去稍微重要一点的一律走本地方案。这条线划清楚用起来就没有心理负担。3.2 结果校验和常见翻车点在线转换最容易被忽略的是校验。因为过程太快人容易产生“已经好了”的错觉实际上问题都藏在结果里。我一般会做三个快速检查。看字数。如果一份十页的文档转出来只有几百字那肯定是失败了要么是扫描件要么是解析中断直接换方案。看开头和结尾。开头几行通常是标题和作者信息结尾是参考文献或者页脚这两处最能暴露问题页眉页脚有没有被当正文混进去最后一段有没有被截断。看特殊字符。搜索一下问号、方块、菱形符号如果成片出现说明编码或字体没处理好。还有一种很隐蔽的失败文字都在但顺序全乱。表现是句子读起来颠三倒四明明是“因此”开头的段落跑到了上一段中间。这种是版面解析出错本质上是工具把多栏内容按横坐标排序结果把左右两栏交错拼接了。判断方法很简单随便挑一段读一遍通顺就没问题读着别扭就是排序错了换本地工具重新来。注意下载下来的文件名经常是一串随机字符批量处理时先重命名成有意义的名称否则过两天你自己都不知道哪个文件对应哪份资料。我习惯用“日期_来源_主题”的格式简单但极其省事。4. 方案三桌面 PDF 编辑器的批量导出4.1 批量任务怎么组织当你手上有几十上百份文件在线站点和办公套件就都不合适了这时候桌面级 PDF 编辑器的价值体现出来。这类软件通常带“批量处理”或者“动作向导”功能可以把“打开—导出为文本—保存到指定目录”这一串操作录制成一个任务然后一次性喂给它几十个文件去泡杯咖啡回来就完事了。批量任务的关键在于目录规划。我一般的做法是建三个文件夹源文件、输出文件、失败清单。源文件只读不改输出文件按同名规则生成失败单独记录。为什么要单独记失败因为批量处理最怕的是“以为都成功了”实际上有三五个文件静默失败你过了两周才发现还得回头重新找。让工具把失败的文件名写进一个日志比事后一个个点开检查高效得多。页面范围也是批量处理里容易忽略的设置。有些文件前几页是封面、目录、版权页转成文本纯属噪音有些文件最后附了几十页广告或者附录也不需要。在批量任务里预设“从第 N 页到第 M 页”能省掉大量后处理工作。当然前提是这批文件的结构一致如果结构参差不齐还是全转再筛更稳妥。4.2 输出设置里的几个决定性选项桌面编辑器导出文本时通常有几个选项别一路点“下一步”跳过。第一个是“保留版面布局”。勾上之后工具会尽量用空格还原文字在页面上的横向位置好处是表格和缩进能看出来坏处是每行前面多出一堆空格正文段落被撑得很宽。我的经验是如果后续要给人读勾上如果后续要给程序做文本分析别勾纯文本更干净。第二个是“识别文本 vs 提取文本”。有的软件提供“OCR 识别”选项即使文件有文本层也会走识别流程这会慢很多而且可能引入错误。有文本层就老老实实提取别多此一举。第三个是“字符编码和换行符”。编码选 UTF-8换行符按目标系统选Windows 环境用 CRLF跨平台处理用 LF。这个细节在单文件上看不出差别但批量处理上千个文件后混用的换行符会让后续脚本出现莫名其妙的解析错误比如某一行的内容被多切了一个空字符串。这套方案我最常用于“结构相对规整、数量中等、需要保留一定版式信息”的场景比如一批格式统一的报告或者教材。它的稳定性比在线站点强很多又不需要写代码属于性价比很高的中间路线。5. 方案四命令行工具批量转换的主力5.1 安装与最小可用命令命令行工具是我日常用得最多的一条路原因很实际快、稳、可脚本化、不占资源。以最经典的 PDF 文本提取工具为例它在多数 Linux 发行版的软件源里直接可装Windows 下也能通过包管理器或者预编译包获得。装好之后最基础的用法只有一行pdftotext input.pdf output.txt这行命令的含义是读入 input.pdf把能提取到的文字写进 output.txt。就这么简单不需要打开界面不需要等加载。我经常在终端里一口气跑几十个文件几秒钟结束。但默认参数出来的结果往往不够好。默认模式会尽量按阅读顺序输出遇到分栏、表格就容易乱。所以真正干活时我基本都会带上参数。最常用的一组是这样的pdftotext -layout -enc UTF-8 -nopgbrk input.pdf output.txt三个参数各有分工下面拆开说。5.2 核心参数详解与组合套路-layout是保留版面布局。开启后工具会根据字符在页面上的坐标用空格把它们摆回大致位置。效果是表格的行列关系、段落的缩进层次都能看出来视觉上接近原文。代价是每行前面可能有一长串空格正文被拉得很宽。我的用法是需要人读的场合开需要机器处理的场合关。-enc UTF-8是明确指定输出编码。不指定的话工具可能按本地语言环境走在跨机器、跨系统传输时就容易出乱码。这个参数属于“写上不亏”的类型养成习惯就好。-nopgbrk是不要在页与页之间插入分页符。默认情况下工具会在每页结束处插一个换页字符本意是保留分页信息但对纯文本处理来说就是噪音——你按行处理时会莫名其妙多出一堆空行或者控制字符。除非你确实需要知道每页的边界否则关掉更省心。还有几个参数在特定场景下非常有用。-f 和 -l控制起止页比如-f 3 -l 10就是只转第 3 到第 10 页处理大部头的时候能省不少时间。-raw是按内容流原始顺序输出不走版面重排遇到那些坐标乱七八糟、重排后反而更乱的文件这个模式有时候能救命。-bbox会额外输出每个词的坐标信息做深度版面分析时才用得上日常转换不必碰。组合起来我常用的两套是这样的# 给人看的版本保留版式 pdftotext -layout -enc UTF-8 -nopgbrk report.pdf report.txt # 给程序处理的版本纯文本流 pdftotext -raw -enc UTF-8 -nopgbrk report.pdf report_raw.txt同一份文件两套都跑一遍对比一下哪个结果更通顺用哪个。这招听起来笨但比我凭经验猜参数快多了。5.3 批量脚本与失败兜底单个文件转换没什么技术含量真正提效的是批量。下面这段脚本我用了很久逻辑很简单遍历目录下所有 PDF逐个转换记录成功和失败。#!/usr/bin/env bash set -u SRC_DIR./pdf OUT_DIR./txt LOG./convert.log mkdir -p $OUT_DIR : $LOG for f in $SRC_DIR/*.pdf; do [ -e $f ] || continue base$(basename $f .pdf) out$OUT_DIR/$base.txt if pdftotext -layout -enc UTF-8 -nopgbrk $f $out 2$LOG; then size$(wc -c $out) if [ $size -lt 200 ]; then echo [WARN] 输出过小 ${size}B: $base $LOG else echo [OK] $base (${size}B) $LOG fi else echo [FAIL] $base $LOG fi done这段脚本里最值钱的不是转换那一行而是那个“输出过小”的判断。命令行工具对扫描件是不会报错的它只会安安静静地生成一个空文件或者只有几个字节的文件然后返回成功。如果你不看日志就会以为全都转好了。设一个字节数阈值把可疑文件挑出来后面再单独用 OCR 处理这一步能省掉大量返工。提示文件名里有空格、括号、中文标点时脚本里一定要给变量加双引号否则路径会被截断。我最早写批量脚本时被这个坑了整整一个下午几十个文件只转出来三个还找不到原因。6. 方案五Python 脚本把转换做成流水线6.1 两个主流库怎么选到了需要定制化的阶段就该上脚本了。Python 生态里做 PDF 文本提取常被拿来比较的是两个方向一个偏重精细控制能拿到每个字符的坐标、字号、字体另一个偏重速度底层是 C 实现处理大文件非常快。前者适合需要做版面分析、表格还原、区域裁剪的场景后者适合“我只要文字越快越好”的批量任务。我的选择逻辑是文件数量在一百以内、需要精细处理用前者上千份、只取正文用后者两者都装先跑快的发现结果不满意再用慢的补刀。这不是模棱两可是实际工作中的常态——你不可能一开始就知道哪份文件会出问题先跑一遍看结果比纠结选型高效。安装很简单用包管理器一行搞定pip install pdfplumber pymupdf两个库的接口风格差别不小。精细控制那个库用上下文管理器打开按页遍历每页调提取方法速度型那个库直接打开文档对象按页号取文本。代码都很短下面直接给完整版本。6.2 一份可直接用的批处理脚本下面这段是我实际在用的骨架包含了打开、提取、清洗、写文件、异常兜底五个环节。import os import re import sys import fitz # PyMuPDF SRC_DIR ./pdf OUT_DIR ./txt MIN_CHARS 100 def clean_text(s: str) - str: # 统一换行 s s.replace(\r\n, \n).replace(\r, \n) # 合并被硬换行拆断的中文行 s re.sub(r(?[\u4e00-\u9fa5。、】])\n(?[\u4e00-\u9fa5【]), , s) # 去掉纯页码行 s re.sub(r^\s*[-—]?\s*\d{1,4}\s*[-—]?\s*$, , s, flagsre.M) # 压缩连续空行 s re.sub(r\n{3,}, \n\n, s) return s.strip() def convert(path: str) - tuple[str, str]: doc fitz.open(path) parts [] for page in doc: parts.append(page.get_text(text)) doc.close() return \n.join(parts), os.makedirs(OUT_DIR, exist_okTrue) report [] for name in os.listdir(SRC_DIR): if not name.lower().endswith(.pdf): continue src os.path.join(SRC_DIR, name) dst os.path.join(OUT_DIR, os.path.splitext(name)[0] .txt) try: raw, _ convert(src) text clean_text(raw) with open(dst, w, encodingutf-8) as f: f.write(text) flag OK if len(text) MIN_CHARS else SUSPECT report.append((name, len(text), flag)) except Exception as e: report.append((name, 0, fERROR:{type(e).__name__})) for name, n, flag in report: print(f{flag:8s} {n:8d} {name})跑完之后看最后一列的输出SUSPECT的进入 OCR 队列ERROR的单独排查。这套流程的核心思想是“先分流、再精修”不要指望一次转换就完美把问题文件挑出来才是效率的关键。6.3 参数调优为什么你的结果和别人不一样同样的库不同人跑出来效果差很多差别往往在这几个参数上。第一个是行容差。精细提取库在判断“这两个字符是不是同一行”时靠的是纵坐标差值默认容差偏小遇到稍微倾斜的扫描件或者行距不均的排版同一行会被拆成两行甚至每个字一行。把容差调大一点比如从默认的 3 调到 5 到 8合并效果会明显改善。反过来如果原文行距很密调太大会把两行粘成一行所以要拿几页试。第二个是字符间距容差。它决定“这两个字符之间隔多远才算插了空格”。中文排版里字距常常不均匀容差太小会在一句话里塞进一堆空格容差太大又会把本来该分开的词粘在一起。我的习惯是先设成默认值跑一页数一数正文里多余的单个空格有多少多就往上调一点。第三个是排序方式。默认按坐标从上到下、从左到右排这对单栏文档没问题对双栏文档就是灾难。有些库提供“按块”提取先把页面切成文本块再按块的顺序输出双栏场景下效果好得多。判断方法很简单如果转出来的句子读着颠三倒四但每句话本身是完整的那就是排序问题换块模式。注意脚本写好后别急着跑全量先挑五种不同类型的文件各跑一遍——纯文字、双栏、带表格、带图注、扫描件。这五类过了剩下的基本都是它们的变体能省掉大半的返工。7. 方案六扫描件 OCR 流水线7.1 渲染分辨率是成败的第一道关扫描件没有文本层只能靠识别。而识别的第一步不是识别本身是把 PDF 页面渲染成图像。这一步的分辨率选错后面怎么调参都是白费。原理很直接OCR 引擎认字靠的是笔画特征笔画太细、像素太少特征就丢了。分辨率太低字糊成一团分辨率太高文件巨大、速度变慢而且过度插值反而会产生伪影。经验值是 300 DPI这是一个在清晰度和成本之间比较平衡的点。具体算一下A4 纸的尺寸是 210mm × 297mm换算成英寸是 8.27 × 11.69。300 DPI 下渲染出来的像素是 8.27 × 300 ≈ 248111.69 × 300 ≈ 3508也就是大约 2480 × 3508 像素。这个尺寸下人眼看到的文字边缘是连续的引擎也能抓到足够的笔画细节。如果原始扫描件本身只有 150 DPI 的信息量你强行渲染到 300 DPI 也不会变清楚只是把模糊放大了这种情况反而应该保持原分辨率靠预处理去噪。用脚本渲染的写法大概是这样import fitz doc fitz.open(scan.pdf) for i, page in enumerate(doc): pix page.get_pixmap(dpi300, colorspacefitz.csGRAY) pix.save(fpage_{i:04d}.png)这里顺手设成灰度是有意为之——OCR 只关心明暗对比不关心颜色转灰度能砍掉三分之二的数据量速度明显提升准确率基本不受影响。7.2 预处理四步不做这一步准确率差一半渲染出来的图直接丢给引擎准确率通常只能到七八成。加上预处理同样的引擎能提到九成以上。四步按顺序来。第一步灰度化。如果是彩色扫描先转成单通道。彩色信息对认字没用反而会让二值化的时候出现色块干扰。第二步二值化。把灰度图变成黑白两色。这里别用固定阈值用自适应阈值按局部区域算阈值这样即使页面一边亮一边暗扫描仪打光不均很常见也能保住细节。固定阈值的典型失败是页面左上角清晰右下角全黑或者全白。第三步去噪。扫描件上常有细小的黑点、纸张纤维、装订孔。用中值滤波能去掉大部分孤立噪点同时保住笔画边缘。注意核大小别开太大3×3 通常够用开大了字会变粗、笔画粘连。第四步纠偏。扫描的时候纸稍微歪一点人眼看不出但引擎按水平方向切行的时候就会错位表现为一行字被切成两半或者两行被粘在一起。检测倾斜角的方法很简单找出所有文字块的边界算最小外接矩形的旋转角然后反向旋转。一般倾斜在两度以内纠偏之后识别率提升非常明显。这四步做完图就“干净”了。我见过很多人跳过预处理直接调引擎参数调半天没效果其实是输入的图本身就有问题——脏的输入不会因为参数调得好就变干净。7.3 引擎参数语言包和版面模式预处理搞定接下来是调用引擎。最容易忽略的是语言包。默认安装往往只带英文识别中文会输出一堆莫名其妙的拉丁字母。装中文简体语言包识别时用-l chi_sim中英混排的文档用-l chi_simeng让引擎同时加载两套模型混排段落才不会一半好一半坏。版面模式PSM的参数更关键它告诉引擎“这一页大概长什么样”。常用的几个值模式值含义适用场景3全自动分页分析默认适合大多数规整文档4假设为单列可变尺寸文本单栏正文、无表格6假设为统一文本块版面干净、整页连续文字11稀疏文本票据、表单、零散字段12稀疏文本加方向检测旋转过的页面我的习惯是先用 3 跑一页看效果如果出现整段丢失或者顺序错乱降到 6 或者 4 再试。表单类的文件直接上 11不要用默认值默认模式会试图把整页当成文章来分析结果把字段全串起来。一条完整的命令长这样tesseract page_0001.png out_0001 -l chi_simeng --psm 6 -c preserve_interword_spaces1最后那个参数是保留词间空格对中文影响不大但中英混排的文档开了之后英文单词之间不会粘成一片。7.4 后处理纠错把准确率再往上顶一截OCR 出来的文本一定有错问题是怎么低成本地修。我的做法是建一个替换规则表把高频错误固化下来每次跑完自动过一遍。高频错误基本集中在几类形近字混认比如“己”和“已”、“未”和“末”、数字和字母混认“0”和“O”、“1”和“l”、标点符号漂移中文逗号变成英文逗号、句号变成点。前两类需要结合上下文判断不好自动修第三类最好办直接做正则替换。import re def fix_ocr(s: str) - str: s s.replace(, ).replace(。, 。) s re.sub(r(?[\u4e00-\u9fa5])\s(?[\u4e00-\u9fa5]), , s) s re.sub(r[ \t]{2,}, , s) return s第二行是去掉中文字符之间被误插的空格这一条在处理 OCR 结果时特别有用因为引擎经常在汉字的笔画间隙里“看到”空格。提示OCR 出来的结果永远不要当成最终稿直接使用。哪怕准确率看着很高关键的数字、日期、名称也必须人工抽查。我吃过亏——一份统计表转出来准确率目测九成五结果偏偏把“3.6”认成了“8.6”一个数字毁了整张表。8. 转换后的清洗与质量校验8.1 断行、页码、页眉页脚怎么批量处理不管用哪种方案转出来的原始文本都是“半成品”。最常见的问题是硬换行原文一个段落转出来变成七八行每行末尾断开。中文没有词间空格断行处直接拼起来就行英文要注意行尾的连字符如果一行以-结尾下一行接上时要把连字符去掉。页码和页眉页脚是另一大噪音源。页码通常是独立成行的纯数字或者带横线的数字用正则就能清掉。页眉页脚麻烦一点因为它们往往每页重复出现我的处理办法是统计所有行找出出现在超过 70% 页面同一位置的行判定为页眉页脚批量删除。这个方法很粗暴但有效唯一要小心的是某些书的章节标题也在页眉重复删之前先抽样看一眼。还有一个隐蔽的坑是零宽字符和软连字符。有些 PDF 在排版时插入了不可见的断字标记复制出来看着正常实际上字符串里多了一个看不见的字符导致你后续做关键词匹配永远匹配不上。处理方法是在清洗时统一过滤掉 Unicode 的格式控制字符一行正则的事但不知道的人能查一整天。8.2 三分钟校验法怎么判断转得好不好校验不需要逐字比对三个指标够用。字符数密度。算一下总字符数除以总页数正常的中文文档每页在 800 到 1500 字之间英文在 2000 到 3500 字符之间。如果某份文件算出来只有个位数那肯定是失败了。这个指标能一把筛出所有“静默失败”的文件。替换字符比例。统计文本里 UFFFD那个菱形问号的数量占比超过千分之一就说明编码或字体有问题。这个字符是解码失败的标志出现就一定有环节没处理好。中文占比。一份中文文档如果统计出来汉字占比不到一半说明大量内容变成了乱码或者符号需要回退重转。这三个指标写进脚本跑完自动生成一张表标红异常项。校验指标正常区间异常含义处理方向每页字符数中文 800-1500过低说明提取失败检查是否扫描件替换字符占比小于 0.1%编码或字体缺失换编码、换工具汉字占比大于 60%大量乱码排查文本层连续空行数小于 3版面解析异常调整布局参数9. 常见问题与排查速查表9.1 乱码类问题的排查顺序乱码是最常见也最让人抓狂的问题。排查要按顺序来别乱试。先确认文件是不是扫描件。前面说过的三步自检走一遍如果是图片乱码是必然的直接上 OCR别在文本层方案上浪费时间。如果有文本层但复制出来是乱码看乱码的形态。如果是一堆方框或者问号那是字体没有嵌入字符的视觉形状有但编码映射丢了这种情况任何文本提取工具都救不回来只能 OCR。如果是一串看似有规律的拉丁字母或者奇怪符号那是字符映射表缺失可以试试换工具某些工具在映射缺失时会走启发式还原成功率不高但值得一试。如果换了两三个工具都是乱码别再试第四个了直接 OCR。我见过有人为了省事试了十几个工具花了两小时其实 OCR 五分钟就搞定了。9.2 排版类问题的排查方向文字都在但顺序乱了问题出在版面解析。先看是不是多栏如果是双栏把提取模式改成“按块”或者“按列”很多工具提供这个选项。如果没提供用带坐标输出的模式拿到每个字符的位置自己按列切分——左边的归左栏右边的归右栏分别排序再拼接。表格串行是另一个高频问题。表格在 PDF 里本质上是靠坐标对齐画出来的没有真正的行列结构。工具提取时只能按位置猜猜错就串。精细提取的库通常有表格识别功能能返回二维数组比自己写逻辑靠谱得多。如果表格结构复杂合并单元格、跨页识别效果会打折这种情况我一般建议放弃自动提取转成图片后人工核对比反复调参省时间。页眉页脚混进正文前面说过用频率统计处理。还有一个变体是脚注脚注文字常常在页面底部按阅读顺序排会被插到正文中间读起来莫名其妙。处理办法是按纵坐标切分页面底部的区域单独提取附加到页面末尾并加标记。9.3 速查表症状对原因对处理症状最可能的原因处理动作输出文件几乎为空扫描件无文本层走 OCR 流水线满屏方框或问号字体未嵌入OCR 识别拉丁字母乱串ToUnicode 映射缺失换工具试一次不成则 OCR句子顺序颠倒多栏排版按行排序切换块模式或按列切分表格内容串行坐标对齐被误判用表格识别功能段落被拆成单行行容差过小调大纵向容差中文之间多空格字符间距容差过小调大横向容差页眉页脚混入正文未做区域过滤按频率统计剔除OCR 结果错字多分辨率低或未预处理提到 300 DPI 并二值化批量处理后文件缺失路径含空格未加引号变量加双引号10. 一些踩过坑之后的实操心得先说一个被普遍低估的点转换之前先做样本测试。不管你有多少文件先拿三到五份代表性的跑一遍确认参数、确认流程、确认输出格式然后再上全量。我最早图快直接几百份一起跑结果参数不对全部推倒重来浪费的时间是测试的几十倍。这个习惯看起来慢实际上是唯一快的做法。第二个心得是保留中间产物。转换过程中生成的图片、临时文本、日志别急着删。排查问题的时候这些东西就是证据链。我曾经遇到一份文件转出来少了中间三页查了半天以为是工具 bug最后发现是原始 PDF 那三页本身是空白页嵌了图片而图片里其实有字——如果当时把渲染的图片删了我永远发现不了。第三个是不要迷信准确率数字。OCR 报出来的置信度、工具宣传的识别率都只能当参考。真正决定结果能不能用的是你的具体需求如果只是做全文检索错几个字不影响如果要做数据抽取一个数字错了就是致命的。所以验收标准要按用途定别拿一个通用指标套所有场景。最后一个关于工具选择别追求一套方案打天下。我现在的实际工作流是三段式的——命令行先扫一遍分流脚本做清洗和后处理OCR 兜底处理脏文件。三套东西各管一段加起来比任何一个“万能工具”都稳。你也不需要一步到位先从一条路走通遇到瓶颈再加下一段这样学习成本最低也不会因为工具太复杂而放弃。真要说有什么一句话的经验那就是先看清楚文件再选工具最后一定要校验。顺序错了工具再好也白搭。