PDF是一种查看方便但解析起来非常不方便的工具,不理解为什么到现在还没对这个问题从源头优化一下。对PDF文件的解析,一般分成以下2种:
1、文字版PDF(打开PDF后可以选中文字):对pdf源文件的解析;
2、扫描版PDF:将pdf转化成图像再解析。
一、判断文件类型为PDF
# 方法一:filetype文件可判断PDF、JPEG等多种文件类型 import filetype print(filetype.guess(file_path)) # <filetype.types.archive.Pdf object at 0x7fc2b8d947b8> # 方法二:二进制读取文件进行判断 binfile = open(file_path, 'rb') # 二制字读取 binfile.seek(0) # 文件游标移动,从位置0开始 print(binfile.read(10)) # b'%PDF-1.4\r\n'
讯享网
二、判断是文字版还是扫描版PDF
目前没有找到特别优雅的方法来通过python代码区分,采用的是读取第一页(或所有页)基于是否包含文字来进行区分。网上有个人也是采用了这个方案:
讯享网https://github.com/dothinking/pdf2docx/issues/99
下文用了pdfplumber和fitz两种方法来进行源文件所有页的解析,如场景特殊且对速度要求高,可以改成第一页。
import fitz import pdfplumber import time def fitz_judee_pdf(filename): doc = fitz.open(filename) for page in doc: # print(page.getText()) if page.getText(): return True return False def pdfplumber_judee_pdf(filename): doc = pdfplumber.open(filename) for page in doc.pages: # print(page.extract_words()) if page.extract_words(): return True return False t0 =time.time() print(fitz_judee_pdf(file_path)) print(time.time()-t0) t0 =time.time() print(pdfplumber_judee_pdf(file_path)) print(time.time()-t0)
三、pdf 解析文本
公认比较好用的pip库是pdfplumber,此外fitz也可以,经费够可以调pdflux这种服务商。fitz仅处理文本,pdfplumber还可以处理表格。
3.1 pdfplumber解析文本
PDFPlumber是基于 PDFMiner 构建的 PDF 解析器,微软构建DocBank(大规模文档布局标注数据集)用到了这个库。不能100%还原表格,支持可视化调试。在mac上解析某个markdown生成的pdf时遇到了一个坑,解析出来的文字是cid编码,解析普通的pdf没有问题。
CID码:PDF包含将字符代码映射到字形索引的CMAP。因此,CID是它映射到的字形在CMAP表中的字符标识。
讯享网import pdfplumber pdf = pdfplumber.open(path) import pandas as pd for page in pdf.pages: # 获取当前页面的全部文本信息,包括表格中的文字 # print(page.extract_text()) # 只提取文字,对表格信息,有简单合并行 # print(page.extract_words()) # 提取字符串的文本、坐标等信息 # print(page.extract_tables()) # 按行元素返回表格信息,无坐标 # print(page.chars) # 按字符而非字符串提取文本、坐标等信息 for t in page.extract_tables(): # for row in t: # print(row) # 得到的table是嵌套list类型,转化成DataFrame更加方便查看和分析 df = pd.DataFrame(t[1:], columns=t[0]) print(df) # 只用第一页测试 break pdf.close()
3.2 fitz 解析文本
import fitz doc = fitz.open(path) whole_pdf = [] for i, page in enumerate(doc): words = page.getTextWords() # [x0, y0, x1, y1, "text", block#, line#, word#] print(words) # for w in words: # print(fitz.Rect(w[:4]), w[4]) break
3.3 pdfplumber和fitz的区别
pdfplumber:速度慢,提取出的文字全
fitz:速度快,例如‘判断是文字版还是扫描版PDF’这部分会比pdfplumber快很多;有些pdf文字的部分文字明明可选但抽不出来?
3.4 cid码
可以简单理解为这种pdf的源文件被加密了,不能用代码直接读。
并且如果直接打开pdf文件去复制黏贴,也会ctrl+v出奇奇怪怪的字符。
cid介绍:[PDF基础知识] CID字库在PDF流程中的应用_(cid:61 pdf-CSDN博客
[PDF基础知识] CID字库在PDF流程中的应用_(cid:61 pdf-CSDN博客
在某个pdf中,pdfplumber 解析出cid码,fitz解析出更奇怪的乱码。因此考虑基于cid码去还原原始文本。仔细研究pdfplumber 解析结果后发现,数字、英文及-可以正常解析,汉字、冒号等不能正常解析。
查询网络信息得知,可以通过char(int(i)),来将cid码转为字符串。但我这里转化后还是乱码,某次翻到某篇文章说可以用分段的方式解决偏移https://www.zhihu.com/question/,当时那篇文章是根据汉字、数字、符号划分了三段,代码如下:
Python解析pdf得到的中文CID字库如何变成utf-8或其他编码呢? - 知乎
讯享网if key <= 122: # 数字大小写 rep[_[0]] = chr(key+31) elif key <= 21902: # 中文 rep[_[0]] = chr(key+19146) else: # 中文标点 rep[_[0]] = chr(key+43378)
但并非所有cid码的划分标准都相同,需要自己想办法去解码,比如我遇到的某个pdf在汉字里也要划段,“送检日期”中“送”和“检日期”的偏移不同。
具体这个偏移怎么探测呢?首先试试不偏移的情况,能否直接chr(int(i))转出来。其次,需要自己知道一些映射关系,如知道某些字符串到cid的对应关系,然后用以下2个函数测试。
# cid码到字符串 print(char(int(i+a))) # 字符串到ASCII码 print(ord('X'))
理论上应该有个映射表集,不同字库、字体的cid码对应的字符是什么,但是我没有在网上找到相关资料。
l此外解析带表格的pdf还有一些其他方法:
1、pdfminer:较复杂、不能直接还原出表格,据说是pdfplumber的底层
2、tabula:依赖java、识别有问题、难以区分多张表
3、各个表格解析的开源项目,如paddleocr、tablemaster、camelot...
4、各个人工智能服务供应商,注册服务后获取token,需要上传文件后下载,如庖丁科技的pdflux
5、poppler:C++
四、pdf 转 图像
不论是扫描生成的图片型pdf还是word生成的可复制文本型pdf,均可转为图像。
讯享网def pdf2img(file_path, dest_path): zoom_x = 2.0 # horizontal zoom zomm_y = 2.0 # vertical zoom mat = fitz.Matrix(zoom_x, zomm_y) # zoom factor 2 in each dimension doc = fitz.open(file_path) # open document image_paths = [] for page in doc: # iterate through the pages pix = page.getPixmap(matrix=mat) image_path = '{0}_{1}.jpg'.format(dest_path, page.number+1) pix.writeImage(image_path) image_paths.append(image_path) return image_paths

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/120220.html