Python使用PyPDF2實現(xiàn)快速提取PDF文本
前言
在日常辦公和數(shù)據(jù)處理中,PDF文件幾乎無處不在。合同、報告、論文、發(fā)票……每天都有大量PDF文檔需要處理。當我們需要從中提取文字信息時,手動復制粘貼不僅效率低下,而且容易出錯。
Python的PyPDF2庫,正是解決這一痛點的利器。它輕量、純Python實現(xiàn)、無需安裝額外依賴,是初學者入門PDF自動化處理的最佳選擇。
本文將帶你從零開始,用PyPDF2快速提取PDF文本,涵蓋安裝配置、核心操作、元數(shù)據(jù)獲取、中文亂碼避坑等全流程。全程附代碼和圖示,確保你讀完就能上手寫代碼。
一、PyPDF2 是什么?適用場景與核心優(yōu)缺點
1.1 適用場景
PyPDF2是一個純Python的PDF處理庫,能夠在不借助任何外部軟件的情況下,對PDF文件進行各種操作[reference:0]。它在以下場景中表現(xiàn)出色:
- 批量提取PDF文本:從成百上千份報告中提取關鍵詞、摘要或全文
- 合并/拆分PDF:將多個PDF合并為一個文檔,或?qū)⒋笮蚉DF按頁拆分
- 讀取PDF元信息:獲取文檔的作者、標題、創(chuàng)建時間等信息
- 加密/解密PDF:為敏感文檔添加密碼保護
- 頁面旋轉、裁剪、添加水印等基礎頁面操作
1.2 核心優(yōu)缺點
| 維度 | 評價 | 說明 |
|---|---|---|
| 優(yōu)點 | 輕量易上手 | 純Python實現(xiàn),一行pip安裝,API簡潔直觀 |
| 優(yōu)點 | 零外部依賴 | 無需安裝Adobe Acrobat或其他PDF軟件 |
| 優(yōu)點 | 基礎功能全覆蓋 | 合并、拆分、提取、加密等一應俱全 |
| 缺點 | 中文易亂碼 | 對中文字體編碼支持較弱,這是最常見的坑 |
| 缺點 | 文本提取能力有限 | 對復雜排版、表格、掃描件基本失效 |
| 缺點 | 大文件內(nèi)存占用高 | 將整個PDF加載到內(nèi)存,幾百頁可能卡死 |
特別提醒:PyPDF2對中文PDF提取文本時容易產(chǎn)生亂碼。官方原版PyPDF2已停止維護,推薦使用其現(xiàn)代分支 pypdf(API幾乎完全兼容)[reference:1]。下文代碼同時支持兩種寫法,你只需將 import PyPDF2 替換為 import pypdf 即可平滑遷移。
1.3 與其他PDF處理庫的對比
為了讓讀者更清楚PyPDF2的定位,下圖展示了主流Python PDF庫的對比:

一句話選擇建議:日?;A操作用PyPDF2/pypdf;提取中文或表格換pdfplumber;追求性能或處理大型PDF用PyMuPDF;掃描件PDF直接上OCR。
二、環(huán)境準備:pip安裝 + 虛擬環(huán)境配置
2.1 基礎安裝
打開終端/命令提示符,執(zhí)行以下命令:
pip install PyPDF2
如果你決定使用現(xiàn)代分支pypdf(強烈推薦),執(zhí)行:
pip install pypdf
驗證安裝是否成功:
python -c "import PyPDF2; print(PyPDF2.__version__)" # 輸出類似:3.0.0
2.2 虛擬環(huán)境配置(團隊項目推薦)
# 創(chuàng)建虛擬環(huán)境 python -m venv pdf_env # 激活虛擬環(huán)境(Windows) pdf_env\Scripts\activate # 激活虛擬環(huán)境(Mac/Linux) source pdf_env/bin/activate # 在虛擬環(huán)境中安裝 pip install PyPDF2 # 導出依賴清單 pip freeze > requirements.txt
2.3 安裝常見問題
| 錯誤信息 | 原因 | 解決方案 |
|---|---|---|
| No module named 'PyPDF2' | 未安裝庫 | 執(zhí)行 pip install PyPDF2 |
| ImportError: cannot import name 'PdfFileReader' | 新版API變更 | 改用 from PyPDF2 import PdfReader |
| pip install 超時 | 網(wǎng)絡問題 | 換國內(nèi)鏡像:pip install PyPDF2 -i https://pypi.tuna.tsinghua.edu.cn/simple |
三、核心操作:逐頁讀取PDF文本
3.1 初學者最易犯的錯誤
很多新手會這樣寫:
import PyPDF2
with open('example.pdf', 'rb') as file:
reader = PyPDF2.PdfReader(file)
print(reader) # 輸出:<PyPDF2._reader.PdfReader object at 0x...>
打印出來的只是一個內(nèi)存地址,而不是PDF的內(nèi)容[reference:2]。這是因為PdfReader對象代表的是整個PDF文檔的結構,而不是文本本身。
3.2 逐頁提取完整代碼
import PyPDF2
def extract_text_from_pdf(pdf_path):
"""從PDF文件中提取所有文本并打印"""
try:
with open(pdf_path, 'rb') as file:
reader = PyPDF2.PdfReader(file)
print(f"文件共 {len(reader.pages)} 頁\n")
for page_num, page in enumerate(reader.pages):
text = page.extract_text()
print(f"--- 第 {page_num + 1} 頁 ---")
print(text if text else "[該頁無文本或提取失敗]")
print()
except FileNotFoundError:
print(f"錯誤:文件 '{pdf_path}' 不存在")
except Exception as e:
print(f"處理PDF時發(fā)生錯誤:{e}")
# 使用示例
extract_text_from_pdf('example.pdf')
3.3 只提取指定頁面
# 只提取第3頁(索引從0開始,所以第3頁的索引是2)
reader = PyPDF2.PdfReader('example.pdf')
third_page_text = reader.pages[2].extract_text()
print(third_page_text)
3.4 合并多個PDF文件
from PyPDF2 import PdfReader, PdfWriter
def merge_pdfs(pdf_list, output_path):
writer = PdfWriter()
for pdf_file in pdf_list:
reader = PdfReader(pdf_file)
for page in reader.pages:
writer.add_page(page)
with open(output_path, 'wb') as f:
writer.write(f)
print(f"合并完成!共 {len(writer.pages)} 頁,保存至 {output_path}")
# 使用示例
merge_pdfs(['file1.pdf', 'file2.pdf', 'file3.pdf'], 'merged.pdf')
3.5 拆分PDF文件
from PyPDF2 import PdfReader, PdfWriter
def split_pdf(input_pdf, output_dir):
reader = PdfReader(input_pdf)
for i, page in enumerate(reader.pages):
writer = PdfWriter()
writer.add_page(page)
output_path = f"{output_dir}/page_{i+1}.pdf"
with open(output_path, 'wb') as f:
writer.write(f)
print(f"拆分完成!共 {len(reader.pages)} 個文件")
# 只拆分前5頁
def split_first_n_pages(input_pdf, n, output_dir):
reader = PdfReader(input_pdf)
writer = PdfWriter()
for page in reader.pages[:n]:
writer.add_page(page)
with open(f"{output_dir}/first_{n}_pages.pdf", 'wb') as f:
writer.write(f)
四、進階:獲取PDF元信息
PDF文件通常包含元數(shù)據(jù)(Metadata),如作者、標題、創(chuàng)建工具、加密狀態(tài)等。PyPDF2可以輕松讀取這些信息。
4.1 獲取完整元信息
from PyPDF2 import PdfReader
reader = PdfReader('example.pdf')
info = reader.metadata
print("=" * 40)
print("PDF 元信息")
print("=" * 40)
print(f"標題: {info.title}")
print(f"作者: {info.author}")
print(f"主題: {info.subject}")
print(f"創(chuàng)建者: info.creator}")
print(f"生產(chǎn)者: info.producer}")
print(f"頁數(shù): {len(reader.pages)}")
print(f"是否加密: {reader.is_encrypted}")
print("=" * 40)
4.2 處理加密PDF
from PyPDF2 import PdfReader
reader = PdfReader('encrypted.pdf')
if reader.is_encrypted:
try:
# 嘗試解密
reader.decrypt('your_password')
print("解密成功!")
# 現(xiàn)在可以正常提取文本
text = reader.pages[0].extract_text()
print(text)
except Exception as e:
print(f"解密失?。簕e}")
else:
print("文件未加密,直接讀取")
重要提示:PyPDF2對加密PDF的支持有限,僅支持舊式加密算法(RC4),不支持AES-256等現(xiàn)代加密方式[reference:3]。遇到 NotImplementedError: only algorithm code 1 and 2 are supported 錯誤時,說明文件使用了不支持的加密算法,建議換用pikepdf處理[reference:4]。
五、避坑指南:中文亂碼的根源與解決方案
這是初學者在使用PyPDF2時最常踩的坑,值得花一整節(jié)來講清楚。
5.1 亂碼現(xiàn)象長什么樣?
# 原本應該是:"這是一份中文PDF文檔" # 實際輸出: "??è????????PDF??£" # 或者輸出: "?????????"
5.2 中文亂碼的根源(重點理解)
亂碼的根本原因并不復雜。下圖清晰解釋了為什么PyPDF2會提取出亂碼:

簡單來說:PDF中的中文字符存儲的是一串“編號”,需要借助“編碼映射表”才能翻譯成正確的中文。PyPDF2恰恰缺少這個翻譯能力,遇到非標準編碼的中文字體就直接“放棄治療”,輸出占位符[reference:5]。
具體來說,亂碼的根源有以下幾種:
- 字體未嵌入或嵌入不全:PDF使用外部字體,提取時找不到對應關系
- 編碼映射表(ToUnicode CMap)缺失:字符代碼無法映射到Unicode
- PyPDF2本身不支持復雜字體解碼:遇到CID字體、自定義編碼的中文字體時直接輸出亂碼[reference:6]
- 編碼方式不匹配:PDF實際使用GBK編碼,而庫默認按UTF-8解碼
5.3 如何判斷PDF是否“可提取”?
在執(zhí)行代碼之前,建議先手動測試一下PDF的文字是否可選:
from PyPDF2 import PdfReader
def check_pdf_extractability(pdf_path):
reader = PdfReader(pdf_path)
print(f"文件名: {pdf_path}")
print(f"頁數(shù): {len(reader.pages)}")
print(f"是否加密: {reader.is_encrypted}")
# 嘗試提取第一頁的前200個字符
sample = reader.pages[0].extract_text()[:200]
print(f"第一頁預覽: {sample}")
# 檢查生產(chǎn)者信息
producer = reader.metadata.get('/Producer', '未知')
print(f"生產(chǎn)者: {producer}")
# 初步判斷
if any(ord(c) > 127 for c in sample if c):
print(">>> 可能包含非ASCII字符(中文),提取結果可能存在亂碼風險")
else:
print(">>> 僅包含ASCII字符,提取相對可靠")
check_pdf_extractability('test.pdf')
5.4 中文亂碼的臨時解決方案
雖然PyPDF2無法完美解決中文亂碼,但在某些場景下可以通過以下方式緩解:
方案1:使用pdfplumber替代(推薦)
# pip install pdfplumber
import pdfplumber
with pdfplumber.open('chinese_doc.pdf') as pdf:
for page in pdf.pages:
text = page.extract_text()
print(text)
pdfplumber基于PDFMiner,對中文字體支持更穩(wěn)定,API也非常相似[reference:7]。
方案2:使用pypdf(現(xiàn)代分支)加容錯參數(shù)
from pypdf import PdfReader
# 添加strict=False忽略部分解析警告
reader = PdfReader('chinese_doc.pdf', strict=False)
text = reader.pages[0].extract_text()
方案3:處理掃描件PDF(圖片型PDF)
# 圖片型PDF需要先轉換為圖片,再用OCR識別
# pip install pdf2image pytesseract pillow
from pdf2image import convert_from_path
import pytesseract
images = convert_from_path('scanned.pdf')
text = pytesseract.image_to_string(images[0], lang='chi_sim')
print(text)
方案4:編碼后處理
# 嘗試手動修復編碼(僅適用于特定場景)
def fix_encoding(broken_text):
# 嘗試不同的編碼方式
for encoding in ['gbk', 'gb2312', 'big5', 'utf-8']:
try:
return broken_text.encode('latin1').decode(encoding)
except:
continue
return broken_text
text = page.extract_text()
fixed_text = fix_encoding(text)
5.5 避坑總結
| 問題類型 | 表現(xiàn) | 解決方案 |
|---|---|---|
| 文字型PDF | 輸出亂碼(如䏿‡) | 換用pdfplumber |
| 掃描件PDF | 提取為空或全是亂碼 | 走OCR路線 |
| 加密PDF | 報NotImplementedError | 換pikepdf解密 |
| 大文件 | 內(nèi)存暴漲/卡死 | 分批處理或換pypdf |
六、完整可運行代碼:批量處理文件夾內(nèi)所有PDF
以下是一個生產(chǎn)環(huán)境可直接使用的腳本,一鍵提取文件夾內(nèi)所有PDF的文本內(nèi)容,并保存為獨立的TXT文件。
import os
import sys
from pathlib import Path
from PyPDF2 import PdfReader
def extract_text_from_pdf(pdf_path):
"""
從單個PDF文件提取文本
返回: (是否成功, 文本內(nèi)容)
"""
try:
reader = PdfReader(pdf_path)
full_text = []
for page_num, page in enumerate(reader.pages, 1):
text = page.extract_text()
if text:
full_text.append(f"[第{page_num}頁]\n{text}\n")
else:
full_text.append(f"[第{page_num}頁]\n[無文本或提取失敗]\n")
return True, "\n".join(full_text)
except Exception as e:
return False, f"處理失?。簕str(e)}"
def batch_extract_pdfs(input_folder, output_folder, extensions=None):
"""
批量提取文件夾內(nèi)所有PDF的文本
參數(shù):
input_folder: 存放PDF文件的文件夾路徑
output_folder: 輸出TXT文件的文件夾路徑
extensions: 文件擴展名列表,默認為['.pdf']
"""
if extensions is None:
extensions = ['.pdf', '.PDF']
# 創(chuàng)建輸出文件夾
Path(output_folder).mkdir(parents=True, exist_ok=True)
# 收集所有PDF文件
pdf_files = []
for ext in extensions:
pdf_files.extend(Path(input_folder).glob(f"*{ext}"))
if not pdf_files:
print(f"在文件夾 '{input_folder}' 中未找到PDF文件")
return
print(f"共找到 {len(pdf_files)} 個PDF文件,開始處理...\n")
success_count = 0
fail_count = 0
for pdf_file in pdf_files:
print(f"正在處理: {pdf_file.name} ...")
success, content = extract_text_from_pdf(str(pdf_file))
output_path = Path(output_folder) / f"{pdf_file.stem}.txt"
with open(output_path, 'w', encoding='utf-8') as f:
f.write(content)
if success:
success_count += 1
print(f" ? 成功,已保存至: {output_path.name}")
else:
fail_count += 1
print(f" ? 失敗: {content[:100]}")
print(f"\n{'='*50}")
print(f"處理完成!成功: {success_count},失敗: {fail_count}")
print(f"輸出目錄: {output_folder}")
print(f"{'='*50}")
def extract_with_progress(input_folder, output_folder, show_preview=True):
"""
帶進度預覽的批量提取功能
"""
pdf_files = list(Path(input_folder).glob("*.pdf")) + list(Path(input_folder).glob("*.PDF"))
total = len(pdf_files)
for idx, pdf_file in enumerate(pdf_files, 1):
print(f"[{idx}/{total}] 處理: {pdf_file.name}")
success, content = extract_text_from_pdf(str(pdf_file))
if show_preview and success:
preview = content[:200].replace('\n', ' ')
print(f" 預覽: {preview}...")
output_path = Path(output_folder) / f"{pdf_file.stem}.txt"
with open(output_path, 'w', encoding='utf-8') as f:
f.write(content)
print(f" ? 已保存\n")
if __name__ == "__main__":
# 方式1:直接運行
INPUT_DIR = "./pdfs" # 存放PDF的文件夾
OUTPUT_DIR = "./output" # 輸出TXT的文件夾
# 方式2:命令行傳參
if len(sys.argv) >= 3:
INPUT_DIR = sys.argv[1]
OUTPUT_DIR = sys.argv[2]
batch_extract_pdfs(INPUT_DIR, OUTPUT_DIR)
# 如果需要更詳細的處理進度,使用以下函數(shù)
# extract_with_progress(INPUT_DIR, OUTPUT_DIR, show_preview=True)
七、總結與延伸建議
7.1 本文核心要點回顧
| 知識點 | 關鍵內(nèi)容 |
|---|---|
| 安裝配置 | pip install PyPDF2,推薦同時安裝pdfplumber作為備選 |
| 文本提取 | 三步走:PdfReader → pages → .extract_text() |
| 合并/拆分 | 使用PdfWriter添加/寫入頁面 |
| 元數(shù)據(jù) | reader.metadata獲取標題、作者等信息 |
| 中文亂碼 | 根源在于字體編碼映射缺失,推薦pdfplumber替代 |
7.2 PyPDF2 vs pypdf 版本選擇建議
| 版本 | 維護狀態(tài) | 推薦度 | 適用場景 |
|---|---|---|---|
| PyPDF2 1.x~2.x | 已停止 | ? | 不推薦 |
| PyPDF2 3.x | 最終版 | ?? | 短期使用 |
| pypdf | 活躍更新 | ????? | 強烈推薦 |
只需將 import PyPDF2 改為 import pypdf,from PyPDF2 import xxx 改為 from pypdf import xxx,代碼幾乎無需其他改動即可平滑遷移。
7.3 進階學習方向
- pdfplumber:提取中文PDF文本、表格數(shù)據(jù)的首選替代方案
- PyMuPDF:追求極致性能時使用,速度遠超PyPDF2
- pikepdf:處理加密PDF、優(yōu)化合并后體積時使用
- PaddleOCR:處理掃描件PDF時使用,中英文識別準確率高
一點提醒:任何工具都有其邊界。PyPDF2最適合處理西文、無加密、文本型PDF的輕量級操作。遇到中文亂碼、掃描件、大文件等場景,及時切換工具往往比“硬扛”更高效。
到此這篇關于Python使用PyPDF2實現(xiàn)快速提取PDF文本的文章就介紹到這了,更多相關Python PyPDF2提取PDF文本內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Python filter()及reduce()函數(shù)使用方法解析
這篇文章主要介紹了Python filter()及reduce()函數(shù)使用方法解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-09-09
利用Python監(jiān)控設備電池電量并發(fā)送通知
在日常使用電子設備時,及時了解電池電量狀態(tài)并進行合理充電是非常重要的,本文將使用Python進行設備電池電量的監(jiān)控并發(fā)送通知,有需要的可以了解下2025-03-03
利用Python封裝MySQLHelper類實現(xiàn)數(shù)據(jù)庫的增刪改查功能
Python 連接 MySQL 的方法有很多,常用的有 pymysql 和 mysql-connector-python 兩種庫,本文主要介紹了如何封裝一個MySQLHelper類,實現(xiàn)對數(shù)據(jù)庫的增刪改查功能,感興趣的可以了解一下2023-06-06

