1.环境配置
!pip install PyPDF2 pdfplumber
PyPDF2 是用来处理 PDF 文件的库,主要功能包括PDF 文件读取、合并、拆分、旋转,可以从 PDF 中提取纯文本,尽管它的提取效果有限,特别是对于扫描版 PDF 文件。
pdfplumber 是比 PyPDF2 更强大的 PDF 处理库,特别擅长处理 PDF 中的表格和文本,能够高效地提取 PDF 的文本内容,并且对于表格的处理更为精确。
2.使用 PyPDF2提取文本
import PyPDF2
# 打开PDF文件
with open('D:/program-OCR/data-PDF-TXT/book.pdf', 'rb') as file:
reader = PyPDF2.PdfReader(file)
text = ''
# 提取每一页的文本
for page in reader.pages:
text += page.extract_text()
# 将提取的文本保存为TXT文件
with open('D:/program-OCR/data-PDF-TXT/output-book-PyPDF2.txt', 'w', encoding='utf-8') as output_file:
output_file.write(text)
rb 模式表示以二进制方式读取文件,适用于 PDF 文件等非文本文件。with open 是 Python 常用的文件操作方法,使用它可以确保在文件操作完后自动关闭文件,避免资源泄露。'w' 表示写入模式,如果文件不存在会创建文件,如果文件已存在会覆盖原有内容。
3.使用 pdfplumber提取文本
import pdfplumber
with pdfplumber.open('D:/program-OCR/data-PDF-TXT/book.pdf') as pdf:
text = ''
for page in pdf.pages:
text += page.extract_text()
# 保存为TXT文件
with open('D:/program-OCR/data-PDF-TXT/output-book-pdfplumber.txt', 'w', encoding='utf-8') as output_file:
output_file.write(text)
with 语句确保文件在操作完成后自动关闭,pdf.pages 是包含 PDF 文件所有页面的列表。page.extract_text() 会提取该页面的文本内容,返回字符串。如果页面的内容是纯文本而没有复杂的排版,extract_text() 会返回相对干净的文本。pdfplumber 提取文本相较于其他库更注重排版和结构,因此如果 PDF 文件的文本排版比较复杂,pdfplumber 能够更好地保留原有的结构。
4.使用difflib比较相似度
import difflib
# 读取两个TXT文件
with open('D:/program-OCR/data-PDF-TXT/output-book-PyPDF2.txt', 'r', encoding='utf-8') as file1:
pyPDF2_text = file1.read()
with open('D:/program-OCR/data-PDF-TXT/output-book-pdfplumber.txt', 'r', encoding='utf-8') as file2:
pdfplumber_text = file2.read()
# 使用difflib对比两者的相似度
similarity = difflib.SequenceMatcher(None, pyPDF2_text, pdfplumber_text).ratio()
print(f"两个文件的相似度为: {similarity:.2f}")
difflib常用于文本比对,可以通过计算序列的相似度来判断两个文本的相似度。SequenceMatcher 的 ratio() 方法返回0 到 1 之间的浮动值,值越接近 1,说明文本越相似;值越接近 0,说明文本差异越大。表示两个文本之间的相似度。None 默认参数,表示不使用自定义的比较函数。
5.检查段落分隔或格式化差异
# 检查文本是否有段落分隔
print(pyPDF2_text[:1000]) # 查看PyPDF2提取的文本开头部分
print(pdfplumber_text[:1000]) # 查看pdfplumber提取文本开头部分
段落分隔检查,PyPDF2 和 pdfplumber 提取文本可能会因为解析方式不同而产生格式差异。例如,某些段落在一个方法中可能被正确分隔,而另一个方法可能没有分隔符,导致文本连续。可以通过查看输出的开头部分,检查是否有段落之间的空行,或者是否存在一些特殊字符(如换行符 \n)来判断文本是否正确分段。
文本内容对比,打印文本前1000个字符可以快速了解提取文本内容是否有格式错误或提取不完全的问题。例如,某些词语可能会缺失,或某些格式可能被错误地解析为一行连续文本。
6.检查乱码或错误字符
# 输出两种方法中是否有乱码或错误字符
print(pyPDF2_text[:2000]) # 查看PyPDF2提取的前2000个字符
print(pdfplumber_text[:2000]) #查看pdfplumber提取前2000个字符
检查乱码或编码错误,PDF 提取过程中,文本的字符编码可能会出现问题,导致某些字符无法正确显示,或者出现乱码。通过查看前2000个字符,可以帮助快速发现这些问题。
检查是否有不正确格式或符号,某些提取工具可能会在提取过程引入额外符号或格式问题,例如多余的换行符、特殊符号或不可见字符。通过对比两者的输出,可以验证是否存在格式错误。
7.测量运行时间
import time
# 测量PyPDF2的运行时间
start_time = time.time()
# PyPDF2提取代码
end_time = time.time()
print(f"PyPDF2提取时间: {end_time - start_time:.2f}秒")
# 测量pdfplumber的运行时间
start_time = time.time()
# pdfplumber提取代码
end_time = time.time()
print(f"pdfplumber提取时间: {end_time - start_time:.2f}秒")
time模块提供了许多与时间相关的功能,其中time.time() 用来获取当前的时间戳(单位为秒)。通过记录代码执行前后的时间戳,可以计算出代码执行的时间差,比较不同方法的性能。
8.计算余弦相似度
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
# 读取提取的TXT文件
with open('D:/program-OCR/data-PDF-TXT/output-book-pdfplumber.txt', 'r', encoding='utf-8') as f:
pdfplumber_text = f.read()
with open('D:/program-OCR/data-PDF-TXT/output-book-PyPDF2.txt', 'r', encoding='utf-8') as f:
pyPDF2_text = f.read()
# 创建TF-IDF向量化器
vectorizer = TfidfVectorizer()
# 将两个文本转化为TF-IDF向量
tfidf_matrix = vectorizer.fit_transform([pdfplumber_text, pyPDF2_text])
# 计算余弦相似度
cosine_sim = cosine_similarity(tfidf_matrix[0:1], tfidf_matrix[1:2])
print(f"两种提取方式的余弦相似度为: {cosine_sim[0][0]:.4f}")
余弦相似度用于衡量两个文本在向量空间中的相似度,值的范围是 [0, 1],值越大表示两个文本越相似。TfidfVectorizer用于将文本数据转换为 TF-IDF(词频-逆文档频率)特征矩阵,TF-IDF 是评估单词在文档集合重要性的统计方法。cosine_similarity用于计算两个文本之间的余弦相似度。fit_transform() 方法将文本数据转化为 TF-IDF 向量,返回稀疏矩阵,表示每个文档中每个词的 TF-IDF 值。
9.计算Jaccard 相似度
def jaccard_similarity(text1, text2):
set1 = set(text1.split())
set2 = set(text2.split())
intersection = len(set1.intersection(set2))
union = len(set1.union(set2))
return intersection / union
jaccard_sim = jaccard_similarity(pdfplumber_text, pyPDF2_text)
print(f"两种提取方式的Jaccard相似度为: {jaccard_sim:.4f}")
Jaccard 相似度是衡量两个集合相似度常用指标,通过计算两个集合交集与并集的比值来衡量它们的相似性,intersection / union是返回交集大小与并集大小之比。Jaccard 相似度的值范围是 [0, 1]:值为 1 表示两个文本完全相同,所有单词都相同。值为 0 表示两个文本完全不同,没有任何相同的单词。