【问题标题】:Python PDF read straight across as how it looks in the PDFPython PDF 直接阅读它在 PDF 中的外观
【发布时间】:2023-03-07 12:17:01
【问题描述】:

如果我在这里使用答案中的代码: 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())

【问题讨论】:

  • 您可以按照物品出现的顺序收集物品,然后重新整理。
  • “任何方式”听起来有点宽泛。您是否检查过 PDFMiner 的文档以查看是否有可能更改此(显然)默认行为?
  • euske.github.io/pdfminer 我没看到。也许有人有另一种不使用 pdfminer 的方法。它变得更加复杂:euske.github.io/pdfminer/programming.html ...也许有人使用对象来做我想做的事。
  • @ScottHunter 斯科特怎么样?你能告诉我一些开始的代码吗?您使用的是哪个 pdf 库? pdfminer?

标签: python pdf pdfminer pypdf2


【解决方案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])

给定页面(第 6 页对应于文档中的第 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 

【讨论】:

    【解决方案2】:

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

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

    您将需要使用更高级的 PDF 库(可能会在简单库之上构建),它将获取每个文本块的 X、Y 位置及其字体信息来确定垂直定位,或自己开发。看起来 JosephA 所说的软件正是这样做的。

    【讨论】:

    • 是的。我想我可能只是购买一个文本转换器并使用命令行,而不是自己尝试做任何事情来重新发明轮子。 A-pdf 看起来不错。
    【解决方案3】:

    我首先查看了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 文件保存在名为“pages”的单独目录中。 Pytesseract 读取每个文件,然后返回文本,然后使用“.replace”对其进行格式化,删除所有行并将文本格式化为一行。

    起点: Tesseract install

    在 python 中使用 tesseract: pytesseract

    使用的训练数据: eng.traineddata

    额外来源: pdf to tiff

    Pytesseract: documentation

    我希望这对你有帮助。不确定这是否是您正在寻找的东西。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-05-26
      • 2022-01-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-12
      • 1970-01-01
      相关资源
      最近更新 更多