-->

提取文本使用PdfMiner和PyPDF2梅杰斯列(Extract Text Using PdfMi

2019-08-18 12:32发布

我试图解析使用pdfMiner PDF文件的文本,但提取的文本被合并。 我使用从以下链接的PDF文件。

PDF文件

我好与任何类型的输出(文件/串)。 这里是返回所提取的文本字符串作为对我,但由于某些原因代码,列合并。

from pdfminer.converter import TextConverter
from pdfminer.layout import LAParams
from pdfminer.pdfinterp import PDFResourceManager, process_pdf
import StringIO

def convert_pdf(filename):
    rsrcmgr = PDFResourceManager()
    retstr = StringIO()
    codec = 'utf-8'
    laparams = LAParams()
    device = TextConverter(rsrcmgr, retstr, codec=codec)

    fp = file(filename, 'rb')
    process_pdf(rsrcmgr, device, fp)
    fp.close()
    device.close()

    str = retstr.getvalue()
    retstr.close()
    return str

我也曾尝试PyPdf2,但面临着同样的问题。 下面是PyPDF2示例代码

from PyPDF2.pdf import PdfFileReader
import StringIO
import time

def getDataUsingPyPdf2(filename):
    pdf = PdfFileReader(open(filename, "rb"))
    content = ""

    for i in range(0, pdf.getNumPages()):
        print str(i)
        extractedText = pdf.getPage(i).extractText()
        content +=  extractedText + "\n"

    content = " ".join(content.replace("\xa0", " ").strip().split())
    return content.encode("ascii", "ignore")

我也曾尝试pdf2txt.py但无法得到格式化输出。

Answer 1:

最近,我挣扎着类似的问题,虽然我的PDF有稍微简单结构。

PDFMiner使用类称为“设备”来解析PDF中的FIL页面。 基本的设备类是PDFPageAggregator类,它只是解析文本框的文件中。 该转换器类,如TextConverter,XMLConverter和HTMLConverter也把结果输出到文件(或字符串流在你的例子),并做某些内容更详尽的解析。

与TextConverter(和PDFPageAggregator)的问题是,他们没有递归深足的文档结构正确提取不同的列。 另外两个转换器需要大约为显示目的文档结构的一些信息,以便他们收集更详细的数据。 在您的示例PDF两个简单的设备只解析(粗略地)含有列中的整个文本框,这使得不可能(或至少非常困难),以正确地分离不同的行。 这个,我发现非常有效的解决方案,是要么

  • 创建从PDFPageAggregator继承一个新的类,或
  • 使用XMLConverter并使用如分析所生成的XML文档Beautifulsoup

在这两种情况下,你将有不同的文本段相结合,用他们的边框y坐标行。

在一个新的设备类的情况下(“那朵更雄辩,我觉得)你必须要覆盖的方法receive_layout是在渲染过程中获得的呼吁每一页。 然后,该方法递归地解析在每个网页中的元素。 例如,这样的事情可能让你开始:

from pdfminer.pdfdocument import PDFDocument, PDFNoOutlines
from pdfminer.pdfparser import PDFParser
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.converter import PDFPageAggregator
from pdfminer.layout import LTPage, LTChar, LTAnno, LAParams, LTTextBox, LTTextLine

class PDFPageDetailedAggregator(PDFPageAggregator):
    def __init__(self, rsrcmgr, pageno=1, laparams=None):
        PDFPageAggregator.__init__(self, rsrcmgr, pageno=pageno, laparams=laparams)
        self.rows = []
        self.page_number = 0
    def receive_layout(self, ltpage):        
        def render(item, page_number):
            if isinstance(item, LTPage) or isinstance(item, LTTextBox):
                for child in item:
                    render(child, page_number)
            elif isinstance(item, LTTextLine):
                child_str = ''
                for child in item:
                    if isinstance(child, (LTChar, LTAnno)):
                        child_str += child.get_text()
                child_str = ' '.join(child_str.split()).strip()
                if child_str:
                    row = (page_number, item.bbox[0], item.bbox[1], item.bbox[2], item.bbox[3], child_str) # bbox == (x1, y1, x2, y2)
                    self.rows.append(row)
                for child in item:
                    render(child, page_number)
            return
        render(ltpage, self.page_number)
        self.page_number += 1
        self.rows = sorted(self.rows, key = lambda x: (x[0], -x[2]))
        self.result = ltpage

在上面的代码中,每个发现LTTextLine元件被存储在包含的页号,边界框的坐标,并且包含在该特定元素中的文本的元组的有序列表。 这样,你会做一些类似这样的:

from pprint import pprint
from pdfminer.pdfparser import PDFParser
from pdfminer.pdfdocument import PDFDocument
from pdfminer.pdfpage import PDFPage
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.layout import LAParams

fp = open('pdf_doc.pdf', 'rb')
parser = PDFParser(fp)
doc = PDFDocument(parser)
doc.initialize('password') # leave empty for no password

rsrcmgr = PDFResourceManager()
laparams = LAParams()
device = PDFPageDetailedAggregator(rsrcmgr, laparams=laparams)
interpreter = PDFPageInterpreter(rsrcmgr, device)

for page in PDFPage.create_pages(doc):
    interpreter.process_page(page)
    # receive the LTPage object for this page
    device.get_result()

pprint(device.rows)

变量device.rows包含了所有的文本行使用他们的页码和y坐标排列有序列表。 您可以遍历所有的文本行和组线,相同的Y坐标,以形成行,存储列数据等。

我试着用上面的代码来解析您的PDF和列大多正确分析。 然而,一些列是如此之近,一起默认PDFMiner启发式无法将它们分开到自己的元素。 你也许可以解决这个问题通过调整保证金一词参数(在命令行工具pdf2text.py -W标志)。 在任何情况下,你可能想通过(不良记录)来读取PDFMiner API以及通过PDFMiner的源代码,你可以从GitHub获得浏览。 (唉,我不能粘贴的链接,因为我没有足够的代表处点:'<,但你可以希望谷歌的正确回购)



Answer 2:

我想你的代码的第一个块和有一大堆的结果是这样的:

多住户AGARDEN COMPLEX 14945010314370 TO 372WILLOWRD W多重住家AGARDEN COMPLEX 14945010314380 TO 384WILLOWRD W多重住家AGARDEN COMPLEX 149450103141000 TO 1020WILLOWBROOKRD多住户AROOMING HOUSE 198787

我猜你是在一个类似的立场,因为这答案和所有的空格来放置在适当的位置的话,还不如实际可打印空格字符。 你已经与其他PDF库尝试这一事实使我认为这可能是很难对任何PDF库来解析的问题。



文章来源: Extract Text Using PdfMiner and PyPDF2 Merges columns