Python PDF以PDF中的样子直接读取
Python PDF以PDF中的样子直接读取
如果我使用这里的答案中的代码:\n使用Python中的PDFMiner从PDF文件中提取文本?\n当应用于这个PDF文件时,我可以提取出文本:https://www.tencent.com/en-us/articles/15000691526464720.pdf\n然而,你可以看到在“综合收入表”下面,它是按照垂直方向读取的...即... 收入 VAS 在线广告
然后稍后它又读取数字... 我想让它横向读取,即:\n收入 73,528 49,552 73,528 66,392 VAS 46,877 35,108
等等... 有没有办法实现这个?\n寻找除了pdfminer
之外的其他可能解决方案。\n如果我尝试使用这段代码来使用PyPDF2
,并不是所有的文本都会显示出来:\n
# 导入所需模块 import PyPDF2 # 创建一个PDF文件对象 pdfFileObj = open(file, 'rb') # 创建一个PDF阅读器对象 pdfReader = PyPDF2.PdfFileReader(pdfFileObj) # 打印PDF文件中的页数 a=(pdfReader.numPages) # 创建一个页面对象 for i in range(0,a): pageObj = pdfReader.getPage(i) print(pageObj.extractText())
Python PDF read straight across as how it looks in the PDF(如何按PDF中的显示顺序直接读取Python PDF)这个问题的出现的原因是使用PyPDF2库中的extractText函数提取文本后,尝试去掉输出中的换行符,以得到一行的输出结果。然而,输出结果并不理想,并且在输出方面也不够可靠。根据PyPDF2文档的说明,不能依赖这个函数输出的文本顺序,因为如果该函数变得更复杂,文本顺序会发生变化。
为了解决这个问题,我开始探索使用Tesseract的选项。这是一种使用“pdf抽取库”进行偏离的方式,实际上是“构建自己的抽取脚本”。一旦掌握了Tesseract的使用方法,这并不是太困难。在掌握了Tesseract的基础知识后,我花了大约一个小时的时间进行研究。
下面是我使用自己的代码逐页抽取pdf的结果:https://gist.github.com/Benehiko/60862a6be13b3b652b7d506121b95811
请注意,我的代码有一个缺陷,它不能按顺序提取页面。
防止链接失效,以下是代码的示例:
from PIL import Image import pytesseract import subprocess import pathlib import glob import os pathlib.Path("pages").mkdir(parents=False, exist_ok=True) params = ['convert', "-density", "300", 'test.pdf', '-depth', '8', 'pages/test_%02d.tiff'] subprocess.check_call(params) images = glob.glob("pages/*.tiff") for image in images: image = Image.open(image) ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) os.environ["TESSDATA_PREFIX"] = ROOT_DIR + "/tessdata" text = pytesseract.image_to_string(image, lang='eng', nice=0, output_type=pytesseract.Output.STRING).replace("\n", " ") print(text)
代码的解释:
首先将pdf转换为单独的“tiff”图像,因为使用pytesseract读取多页tiff文件时,只会读取第一页。tiff文件保存在名为“pages”的单独目录中。Pytesseract逐个读取文件,并返回文本,然后使用“.replace”对文本进行格式化,删除所有行并将文本格式化为一行。
以下是一些相关的参考链接:
- Tesseract安装:Tesseract install
- 在Python中使用Tesseract:pytesseract
- 使用的训练数据:eng.traineddata
- 相关资源:pdf to tiff
- Pytesseract文档:documentation
希望这能对您有所帮助,不确定是否符合您的要求。
问题出现的原因是PDF文件的构造方式与pyPDF2存在差异。在解析PDF文件以重新构建页面布局时,我遇到了许多相同的问题。
当生成PDF时,每个文本块都根据应用的字体规则和页面上的位置进行定位和渲染(类似于仅使用绝对定位和CSS构建HTML文档)。一个简单的PDF库只会按照文件中定义的顺序返回每个文本块的文本(我曾遇到过页面逆序生成的文档,最后一个段落先定义)。
要解决这个问题,你需要使用更高级的PDF库(可能是基于简单库构建的库),该库将使用每个文本块的X、Y位置以及字体信息来确定垂直定位,或者自己开发解决方案。看起来,JosephA提到的软件正是在做这个工作。
是的,我想我可能会购买一个转换器来将PDF转为文本,并使用命令行而不是试图自己重新发明轮子。A-pdf看起来很不错。
Python PDF read straight across as how it looks in the PDF这个问题的出现的原因是因为默认的PDFMiner参数无法正确识别PDF文件中表格的布局,导致读取的文本顺序不正确。解决方法是通过修改PDFMiner的参数来指定正确的布局信息,以便正确读取PDF中的表格。
在上述内容中,作者推荐使用PDFMiner工具来解决这个问题,并且指出在他的经验中,PDFMiner在这方面的表现比其他开源的Python工具更好。关键是要正确指定laparams
参数,并不使用默认值。这个参数用于向PDFMiner提供关于页面布局的更多信息。由于这里的文本对应具有宽间距的表格,我们需要指示PDFMiner使用较大的字符边距(char_margin
)。
解决这个问题的代码在这里。可以尝试调整超参数以获得最佳结果。
下面是一个示例代码,用于处理问题中的PDF。这里只使用了单页进行演示:
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter from pdfminer.converter import TextConverter from pdfminer.layout import LAParams from pdfminer.pdfpage import PDFPage from io import StringIO def convert_pdf_to_txt(path, pages): rsrcmgr = PDFResourceManager() retstr = StringIO() codec = 'utf-8' laparams=LAParams(all_texts=True, detect_vertical=True, line_overlap=0.5, char_margin=1000.0, #将char_margin设置为一个较大的数值 line_margin=0.5, word_margin=2, boxes_flow=1) device = TextConverter(rsrcmgr, retstr, codec=codec, laparams=laparams) fp = open(path, 'rb') interpreter = PDFPageInterpreter(rsrcmgr, device) password = "" maxpages = 0 caching = True pagenos=set(pages) for page in PDFPage.get_pages(fp, pagenos, maxpages=maxpages, password=password,caching=caching, check_extractable=True): interpreter.process_page(page) text = retstr.getvalue() fp.close() device.close() retstr.close() return text pdf_text_page6 = convert_pdf_to_txt("15000691526464720.pdf", pages=[6])
给定页面的输出结果(第6页对应PDF中的第7页)如下所示。虽然不完美,但是表格的所有数字组件都被捕获在与文本相同的行中。
Page 7 of 11 Unaudited Unaudited 1Q2018 1Q2017 1Q2018 4Q2017 Revenues 73,528 49,552 73,528 66,392 VAS 46,877 35,108 46,877 39,947 Online advertising 10,689 6,888 10,689 12,361 Others 15,962 7,556 15,962 14,084 Cost of revenues (36,486) (24,109) (36,486) (34,897) Gross profit 37,042 25,443 37,042 31,495