有没有Python的方法来识别PDF是否已经进行OCR处理(文本质量差)还是一个可搜索的PDF(文本质量完美)?
使用PDF的元数据
import pprint
import PyPDF2
def get_doc_info(path):
pp = pprint.PrettyPrinter(indent =4)
pdf_file = PyPDF2.PdfFileReader(path, 'rb')
doc_info = pdf_file.getDocumentInfo()
pp.pprint(doc_info)
我发现:
result = get_doc_info(PDF_SEARCHABLE_HAS_BEEN_OCRD.pdf)
{ '/Author': 'NAPS2',
'/CreationDate': "D:20200701104101+02'00'",
'/Creator': 'NAPS2',
'/Keywords': '',
'/ModDate': "D:20200701104101+02'00'",
'/Producer': 'PDFsharp 1.50.4589 (www.pdfsharp.com)'}
result = get_doc_info(PDF_SEARCHABLE_TRUE.pdf)
{ '/CreationDate': 'D:20210802122000Z',
'/Creator': 'Quadient CXM AG~Inspire~14.3.49.7',
'/Producer': ''}
我可以使用PDF元数据中的Creator来检查PDF的类型(真正的PDF还是OCR PDF)吗?
还有其他使用Python的方法吗?
如果这个问题没有解决方案,我如何使用深度学习/机器学习来检测PDF可搜索的类型(真或OCR)?
这是一个视频,帮助理解真PDF和OCR PDF之间的区别:https://www.youtube.com/watch?v=xs8KQbxsMcw
回答:
不久前我遇到了同样的问题!
我开发了(基于某个我无法回想的SO帖子)这个函数:
def get_scanned_pages_percentage(filepath: str) -> float:
""" INPUT: PDF文件的路径 OUTPUT: OCR处理的包含文本的页面百分比"""
total_pages = 0
total_scanned_pages = 0
with fitz.open(filepath) as doc:
for page in doc:
text = page.getText().strip()
if len(text) == 0:
# 忽略“空”页面
continue
total_pages += 1
pix1 = page.getPixmap(alpha=False) # 将页面渲染为图像
remove_all_text(doc, page)
pix2 = page.getPixmap(alpha=False)
img1 = pix1.getImageData("png")
img2 = pix2.getImageData("png")
if img1 == img2:
# print(f"{page.number} was scanned or has no text")
if len(text) > 0:
# print(f"\tHas text of length {len(text):,} characters")
total_scanned_pages += 1
else:
pass
if total_pages == 0:
return 0
return (total_scanned_pages / total_pages) * 100
这个函数如果PDF是包含OCR处理文本的图像,将返回100(或接近100),如果是原生数字PDF,则返回0。
删除所有文本:
def remove_all_text(doc, page):
"""从PDF文档页面(元数据)中删除所有文本"""
page.cleanContents() # 清理页面外观命令的语法
# 清理后的命令源(字节对象)的xref
xref = page.getContents()[0]
cont = doc.xrefStream(xref) # 读取它
# 元数据以字节形式存储,它提取为字节。然后搜索引用文本的标签并删除它。
ba_cont = bytearray(cont) # 可修改版本
pos = 0
changed = False # 指示更改的开关
while pos < len(cont) - 1:
pos = ba_cont.find(b"BT\n", pos) # 开始文本对象
if pos < 0:
break # 未(更多)找到
pos2 = ba_cont.find(b"ET\n", pos) # 结束文本对象
if pos2 <= pos:
break # PDF页面定义中的重大错误!
ba_cont[pos: pos2 + 2] = b"" # 删除文本对象
changed = True
if changed: # 我们确实删除了一些文本
doc.updateStream(xref, ba_cont) # 写回不含文本的命令流