最近遇到这么一个需求:
有大概100万篇研究报告(pdf格式),想要提取出报告中的文本,图表,从而可以利用文章内容搜索报告和报告中的图表。并且还要计算报告之间的内容相似度,在用户点击一篇报告时,可以计算出与这篇报告内容相似程度较高的报告,并做相应推荐。
1、数据的提取
首先的问题是pdf中文本和图片的提取。pdf信息提取使用pdfminer包,截图使用PIL,pdfminer的介绍如下:
https://blog.csdn.net/Fighting_No1/article/details/51038942
图表提取思路:
1、遍历pdf中图片对象,利用返回的坐标截图。(注意pdfminer定义位置的y轴以最底端为0,PIL截图定义的y轴以最顶端为0)但是这样的方法有缺陷,会截出很多不必要的图,如:
需要的图可以正常截,但是缺少了图片标题,而且无法识别表格对象。![在这里插入图片描述](https://img-blog.csdnimg.cn/20190808063834301.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3RhbnNpcjEyMw==,size_16,color_FFFFFF,t_70
表格在pdf中不是一个对象,而是多个文本框和线的组合,因此取不到表的坐标。2、根据图片头尾文本截图。观察到所有图片表头都为 ’图X‘+‘空格:’+图表名称,表尾都为 ‘资料来源:’+资料来源’的形式,可以根据正则表达式匹配到文本,获取文本框的位置,根据文本框位置截图。
这样的方法可以截到,但图表可能跨页,也可能两个图片并排横向排列。因此又对这些情况进行了处理。
文本提取与清洗过程中遇到的困难:
1、文本提取大部分正常,但表格内的文字也会提进去。因为表大部分是数字,而正文中也有数字,是具有意义的,不能把所有数字都屏蔽。所以在后面的分词阶段对数字进行了停用。
2、文本提取有少部分乱码,是由于某些特殊制表符造成python内码识别错误,将gb2312格式中的这些制表符错认为utf-8的文本。由于gb2312是双字节编码,utf-8是三字节编码,如果有一个地方解码出错,后面所有字节都会错,文本的一整段都是乱码。这个问题我都是手动抽查并修改的,但也难保证全部改对。
3、每篇文章最后都有一大段废话(如下图),也是手动提取一系列关键字,找到最后一个关键字然后剔除关键字后面的内容。
# -*- coding: utf-8 -*-
from pdfminer.pdfparser import PDFParser, PDFDocument
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.converter import PDFPageAggregator
from pdfminer.layout import LAParams
from pdfminer.pdfinterp import PDFTextExtractionNotAllowed
from PIL import Image
import fitz
import re
import os
import time
class GetPic:
def __init__(self, filename, password=''):
"""
初始化
:param filename: pdf路径
:param password: 密码
"""
with open(filename, 'rb') as file:
# 创建文档分析器
self.parser = PDFParser(file)
# 创建文档
self.doc = PDFDocument()
# 连接文档与文档分析器
self.parser.set_document(self.doc)
self.doc.set_parser(self.parser)
# 初始化, 提供初始密码, 若无则为空字符串
self.doc.initialize(password)
# 检测文档是否提供txt转换, 不提供就忽略, 抛出异常
if not self.doc.is_extractable:
raise PDFTextExtractionNotAllowed
else:
# 创建PDF资源管理器, 管理共享资源
self.resource_manager = PDFResourceManager()
# 创建一个PDF设备对象
self.laparams = LAParams()
self.device = PDFPageAggregator(self.resource_manager, laparams=self.laparams)
# 创建一个PDF解释器对象
self.interpreter = PDFPageInterpreter(self.resource_manager, self.device)
# pdf的page对象列表
self.doc_pdfs = list(self.doc.get_pages())
# 打开PDF文件, 生成一个包含图片doc对象的可迭代对象
self.doc_pics = fitz.open(filename)
def to_pic(self, doc, zoom, pg, pic_path):
"""
将单页pdf转换为