PDF需先判别类型:文本型用pdfplumber精准提取(含表格与中英文混排),扫描件必须OCR(如pytesseract+pdf2image配中文lang参数),加密PDF须先解密,错误判断将导致提取失败。

PDF 文档不是网页,不能用 requests + BeautifulSoup 直接解析 HTML 那样处理;直接读二进制或用通用文本提取工具(如 pdfminer.six)常会失败——尤其遇到扫描件、加密 PDF、含复杂表格或中文字体嵌入缺失的情况。
判断 PDF 类型:先分清是“可选中文本”还是“纯图像”
这是后续所有操作的前提。错误判断会导致整个流程卡死或返回空字符串。
- 用
pdfplumber打开后检查page.chars或page.extract_text()是否有非空结果;若为空,大概率是扫描件 - 用
PyPDF2.PdfReader读取.is_encrypted属性,加密 PDF 必须先解密(需密码)才能继续 - 用
fitz.open()(即PyMuPDF)调用page.get_text("text"),对比输出长度;若极短但页面明显有内容,倾向是图像型 - 中文字体缺失时,
pdfminer.six可能报UnicodeDecodeError或输出乱码,此时优先换pdfplumber(对中文字体更宽容)
文本型 PDF:用 pdfplumber 提取结构化内容
pdfplumber 是目前对中文排版、表格识别最稳的开源库,它把每页当“画布”,能获取字符坐标、行块、表格边界,适合做精准定位提取。
- 安装:
pip install pdfplumber(注意不是pdfminer) - 基础提取:
pdfplumber.open("file.pdf").pages[0].extract_text()—— 简单场景够用,但换行/空格可能错乱 - 表格提取必须显式调用:
page.extract_tables(),返回二维列表;默认用视觉线检测,若表格无线条,得传vertical_strategy="text"或horizontal_strategy="text" - 避免内存爆炸:大 PDF 别一次性
open()全部页,用with pdfplumber.open(...) as pdf:+ 循环处理单页 - 中英文混排时,
use_text_flow=True参数能改善阅读顺序(尤其多栏),但会略微拖慢速度
扫描件 PDF:必须走 OCR 路线,别硬扛
试图用纯文本提取工具处理扫描件,99% 结果是空字符串或乱码。必须引入 OCR 引擎,且要控制成本与精度平衡。
立即学习“Python免费学习笔记(深入)”;
- 本地轻量方案:用
pytesseract+pdf2image,先转图再识别;pdf2image.convert_from_path()输出 PIL 图像,注意dpi=200是底线,300更稳妥 - 中文识别务必指定语言:
pytesseract.image_to_string(img, lang="chi_sim")(简体)或lang="chi_tra"(繁体);缺lang参数默认只识英文 - 避免白边干扰:OCR 前用
cv2或 PIL 裁黑边、二值化(img.convert("L").point(lambda x: 0 if x )能显著提升准确率 - 云 API(如百度 OCR、腾讯 OCR)适合高精度需求,但要注意接口限流和敏感内容合规风险;别把内部合同直接扔给第三方
常见陷阱与绕过方式
很多失败不是代码写错,而是 PDF 本身“不讲武德”:加密、字体子集、JavaScript 自动跳转、甚至故意插入零宽字符干扰解析。
-
UnicodeEncodeError: 'gbk' codec can't encode character?说明终端或文件写入时编码没设encoding="utf-8",所有open(..., "w")必须加该参数 - 提取出来全是“□□□”或“”?不是 OCR 问题,是 PDF 内嵌字体未映射 Unicode,换
PyMuPDF的page.get_text("html")或启用layout_mode="normal"重试 - 表格列错位、跨页表断开?
pdfplumber默认不跨页合并,需手动缓存上一页末尾行 + 下一页开头行做逻辑拼接 - PDF 含 JavaScript 触发跳转或动态加载内容?Python 库无法执行 JS,这类 PDF 实质是“伪装 PDF 的网页”,得用
playwright截图+OCR,或找原始网页源
真正难的从来不是调哪个函数,而是拿到一个未知 PDF 后,三分钟内判断它属于哪一类、该走哪条技术路径——多试两个库的首屏提取结果,比死磕一个参数有效得多。



















