Python PDF在PDF中的外观直接读取

时间:2018-07-21 21:47:45

标签: python pdf pdfminer pypdf2

如果我在此处使用答案中的代码: Extracting text from a PDF file using PDFMiner in python?

应用于此pdf文件时,我可以提取文字:https://www.tencent.com/en-us/articles/15000691526464720.pdf

但是,您在“合并收入声明”下看到了它的内容,即... Revenues VAS Online advertising,然后再读取数字...我希望将其读出,即:

Revenues 73,528 49,552 73,528 66,392 VAS 46,877 35,108等...有办法吗?

寻找pdfminer以外的其他可能解决方案。

如果我尝试将这段代码用于PyPDF2,则并非所有文字都显示出来:

# importing required modules
import PyPDF2

# creating a pdf file object
pdfFileObj = open(file, 'rb')

# creating a pdf reader object
pdfReader = PyPDF2.PdfFileReader(pdfFileObj)

# printing number of pages in pdf file
a=(pdfReader.numPages)

# creating a page object
for i in range(0,a):
    pageObj = pdfReader.getPage(i)
    print(pageObj.extractText())

4 个答案:

答案 0 :(得分:2)

很难说为什么pdfminer会给您它提取文本的结果。也许它的算法有些问题。

我工作的公司有用于PDF库的示例代码,我使用了TextExtract C#(在测试是否有可能获得所需结果的过程中,这是我的练习)您的文档(说明了如何编写代码来提取PDF文档的文本),并从第7页中提取了以下内容:

  

合并收益表   百万元,除非另有说明   未经审核   未经审核   2018年第一季度   2017年第一季度   2018年第一季度   2017年第四季度   营业额    73,528   49,552   73,528   66,392   增值服务   46,877   35,108   46,877   39,947   在线广告   10,689   6,888   10,689   12,361   其他   15,962   7,556   15,962   14,084   收益成本   (36,486)   (24,109)   (36,486)   (34,897)   毛利   37,042   25,443   37,042   31,495   毛利率   50%   51%   50%   47%   利息收入   1,065   808   1,065   1,156   其他收益净额   7,585   3,191   7,585   7,906   营销费用   (5,570)   (3,158)   (5,570)   (6,022)   一般及行政开支   (9,430)   (7,012)   (9,430)   (8,811)   营业利润   30,692   19,272   30,692   25,724   营业利润率   42%   39%   42%   39%   财务费用净额   (654)   (691)   (654)   (859)   应占联营公司及合营企业的损益   (319)   (375)   (319)   (120)   除所得税前溢利   29,719   18,206   29,719   24,745   所得税费用   (5,746)   (3,658)   (5,746)   (3,123)   本期利润   23,973   14,548   23,973   21,622   净利润   33%   29%   33%   33%   归因于:   公司股权持有人   23,290   14,476   23,290   20,797   非控制性权益   683   72   683   825   非GAAP归属于股东的权益   公司   18,313   14,211   18,313   17,454   归属于母公司股东的每股收益   公司股权持有人   (每股人民币)   -基本   2.470   1.540   2.470   2.206   -稀释   2.435   1.522   2.435   2.177

您可以看到,它正在“请求”返回整个页面。

答案 1 :(得分:1)

与pyPDF2的问题相比,您的问题更多地与PDF文件的结构有关。在解析PDF以重新构建页面布局时,我遇到了许多相同的问题。

生成PDF时,每个文本块都将在页面上定位并根据所应用的字体规则进行呈现(类似于使用绝对位置定位和CSS来构造HTML文档)。一个简单的PDF库将简单地按照文件中定义的顺序从每个块中返回文本(当反向生成页面时,我已经有了文档,最后一段首先定义)。

您要么需要使用更高级的PDF库(可能会在简单库的基础上构建),该库将利用每个文本块的X,Y位置及其字体信息来确定垂直位置,或自己开发。看来 JosephA 正在谈论的软件正是在这样做。

答案 2 :(得分:1)

我首先查找extractText function of PyPDF2,并尝试从输出中“剥离”任何新行,以使您“跨过”页面。

输出不是很理想... output

此外,就您的输出而言,它似乎也不可靠。 从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文件保存在称为“页面”的单独目录中。 Pytesseract读取每个文件,然后返回文本,然后使用“ .replace”将其格式化,该文本将删除所有行并将文本格式化为一行。

开始的地方: Tesseract install

在python中使用tesseract: pytesseract

训练数据: eng.traineddata

其他来源: pdf to tiff

Pytesseract: documentation

希望这对您有所帮助。不确定这是否是您想要的东西。

答案 3 :(得分:1)

您可以使用PDFMiner来完成这项工作,以我的经验,它比那里的其他开源Python工具更好。

关键是正确地指定laparams参数 ,而不是将其保留为默认值。此参数用于为PDFMiner提供有关页面布局的更多信息。由于此处的文本对应于具有宽空格的表,因此我们需要指示PDFMiner使用较大的字符边距(char_margin)。

布局的代码为here。尝试为该特定文档提供最佳结果的超参数。

这是有关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, #set char_margin to a large number
                      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])

给定页面(与文档中的第7页相对应的第6页)的输出看起来像下面的块。这不是完美的方法,但是表格的所有数字部分都与文本位于同一行。

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