python爬pdf的曲线_Python处理PDF-通过关键词定位-截取PDF中的图表

起因:

因为个人原因, 这些天了解了一下Python处理PDF的方法.

首先是PDF转txt, 这个方法比较多, 这里就不再赘述, 主要聊一下PDF中的图片获取.

这里用我自己的例子, 不过具体情况还得具体分析.

工具: pdfminer, pillow, fitz, re

思路:

1.  使用pdfminer解析PDF, 通过当前页的LTpage对象, 获取关键词的position与当前LTpage的size.

2.  使用fitz将当前页的PDF转换为PNG

3.  使用pillow, 通过第一步得到的参数来从第二步得到的PNG中截取目标图表

关键词: "[图表]*\s\d+[::]", "来源[::]"

代码:

1 from pdfminer.pdfparser importPDFParser, PDFDocument2 from pdfminer.pdfinterp importPDFResourceManager, PDFPageInterpreter3 from pdfminer.converter importPDFPageAggregator4 from pdfminer.layout importLAParams5 from pdfminer.pdfinterp importPDFTextExtractionNotAllowed6 from PIL importImage7 importfitz8 importre9 importos10

11

12 classGetPic:13 def __init__(self, filename, password=''):14 """

15 初始化16 :param filename: pdf路径17 :param password: 密码18 """

19 with open(filename, 'rb') as file:20 #创建文档分析器

21 self.parser =PDFParser(file)22 #创建文档

23 self.doc =PDFDocument()24 #连接文档与文档分析器

25 self.parser.set_document(self.doc)26 self.doc.set_parser(self.parser)27 #初始化, 提供初始密码, 若无则为空字符串

28 self.doc.initialize(password)29 #检测文档是否提供txt转换, 不提供就忽略, 抛出异常

30 if notself.doc.is_extractable:31 raisePDFTextExtractionNotAllowed32 else:33 #创建PDF资源管理器, 管理共享资源

34 self.resource_manager =PDFResourceManager()35 #创建一个PDF设备对象

36 self.laparams =LAParams()37 self.device = PDFPageAggregator(self.resource_manager, laparams=self.laparams)38 #创建一个PDF解释器对象

39 self.interpreter =PDFPageInterpreter(self.resource_manager, self.device)40 #pdf的page对象列表

41 self.doc_pdfs =list(self.doc.get_pages())42 #打开PDF文件, 生成一个包含图片doc对象的可迭代对象

43 self.doc_pics =fitz.open(filename)44

45 defto_pic(self, doc, zoom, pg, pic_path):46 """

47 将单页pdf转换为pic48 :param doc: 图片的doc对象49 :param zoom: 图片缩放比例, type int, 数值越大分辨率越高50 :param pg: 对象在doc_pics中的索引51 :param pic_path: 图片保存路径52 :return: 图片的路径53 """

54 rotate =int(0)55 trans =fitz.Matrix(zoom, zoom).preRotate(rotate)56 pm = doc.getPixmap(matrix=trans, alpha=False)57 path = os.path.join(pic_path, str(pg)) + '.png'

58 pm.writePNG(path)59 returnpath60

61 defget_pic_loc(self, doc):62 """

63 获取单页中图片的位置64 :param doc: pdf的doc对象65 :return: 返回一个list, 元素为图片名称和上下y坐标元组组成的tuple. 当前页的尺寸66 """

67 self.interpreter.process_page(doc)68 layout =self.device.get_result()69 #pdf的尺寸, tuple, (width, height)

70 canvas_size =layout.bbox71 #图片名称坐标

72 loc_top =[]73 #来源坐标

74 loc_bottom =[]75 #图片名称与应截取的区域y1, y2坐标

76 loc_named_pic =[]77 #遍历单页的所有LT对象

78 for i inlayout:79 if hasattr(i, 'get_text'):80 text =i.get_text().strip()81 #匹配关键词

82 if re.search(r'图表*\s\d+[::]', text):83 loc_top.append((i.bbox, text))84 elif re.search(r'来源[::]', text):85 loc_bottom.append((i.bbox, text))86 zip_loc =zip(loc_top, loc_bottom)87 for i inzip_loc:88 y1 = i[1][0][1]89 y2 = i[0][0][3]90 name = i[0][1]91 loc_named_pic.append((name, (y1, y2)))92 returnloc_named_pic, canvas_size93

94 defget_crops(self, pic_path, canvas_size, position, cropped_pic_name, cropped_pic_path):95 """

96 按给定位置截取图片97 :param pic_path: 被截取的图片的路径98 :param canvas_size: 图片为pdf时的尺寸, tuple, (0, 0, width, height)99 :param position: 要截取的位置, tuple, (y1, y2)100 :param cropped_pic_name: 截取的图片名称101 :param cropped_pic_path: 截取的图片保存路径102 :return:103 """

104 img =Image.open(pic_path)105 #当前图片的尺寸 tuple(width, height)

106 pic_size =img.size107 #截图的范围扩大值

108 size_increase = 10

109 x1 =0110 x2 =pic_size[0]111 y1 = pic_size[1] * (1 - (position[1] + size_increase)/canvas_size[3])112 y2 = pic_size[1] * (1 - (position[0] - size_increase)/canvas_size[3])113 cropped_img =img.crop((x1, y1, x2, y2))114 #保存截图文件的路径

115 path = os.path.join(cropped_pic_path, cropped_pic_name) + '.png'

116 cropped_img.save(path)117 print('成功截取图片:', cropped_pic_name)118

119 def main(self, pic_path, cropped_pic_path, pgn=None):120 """

121 主函数122 :param pic_path: 被截取的图片路径123 :param cropped_pic_path: 图片的截图的保存路径124 :param pgn: 指定获取截图的对象的索引125 :return:126 """

127 if pgn is notNone:128 #获取当前页的doc

129 doc_pdf =self.doc_pdfs[pgn]130 doc_pic =self.doc_pics[pgn]131 #将当前页转换为PNG, 返回值为图片路径

132 path = self.to_pic(doc_pic, 2, pgn, pic_path)133 loc_name_pic, canvas_size =self.get_pic_loc(doc_pdf)134 ifloc_name_pic:135 for i inloc_name_pic:136 position = i[1]137 cropped_pic_name = re.sub('/', '_', i[0])138 self.get_crops(path, canvas_size, position, cropped_pic_name, cropped_pic_path)139

140

141 if __name__ == '__main__':142 pdf_path = '要处理的PDF的路径'

143 test =GetPic(pdf_path)144 pic_path = 'PNG的保存路径'

145 cropped_pic_path = '截图的保存路径'

146 page_count =test.doc_pics.pageCount147 for i inrange(page_count):148 test.main(pic_path, cropped_pic_path, pgn=i)

本例局限:

1.  目标PDF需要可以用pdfminer里的LTPage对象解析出文字.

2.  PDF中没有跳页的图表.

3.  截图的时候只用了y轴截图, x轴上可能出现多个图表

局限解决方案:

1.  目前没有去尝试, 或许PyPDF2可以试一试?

2.  这里的函数都是处理单页的, 所有在处理连页图片时会出现问题, 不过解决方法也很简单. 就是将 loc_top、loc_bottom设置为全局变量并且加上页码的索引, 这样loc_top和loc_bottm中的元素就能够一一对应. 再加上一个判断, top的y轴坐标比bottom小的话, 就截取两张图片, top的y轴坐标至页尾和bottom的y轴坐标至页头. 有兴趣的可以自己尝试一下.

3.  这个问题的话, 一是可以后期通过其它库再按照一定的方法截取一次; 二是可以在一次截取的时候加上x轴的左坐标来确定目标位置, 因为如果同一y轴范围内只有一个图表的话, x轴右坐标就无关紧要类, 如果同一y轴范围内有两个图标的话, 通过x轴左坐标也能化界, 如果有两个以上的图标时候就需要加上x轴的右坐标了.

结语:

这里只是提供了一种思路, 方法其实还是很不完善的, 很多小细节都没有去解决.

还有一种思路是将PDF转换为PNG之后直接识别其中的关键词左边来获取截图, 这个的话大家也可以去了解一下, 用tesserocr库应该可以解决.

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值