Python 从与副本布局相同的PDF文件中获取数据+;粘贴

Python 从与副本布局相同的PDF文件中获取数据+;粘贴,python,pdf,pdfminer,Python,Pdf,Pdfminer,我有一个过程,我正在寻找自动化的环境从一个PDF文件获得一系列的表。目前,我可以通过在任何查看器(Adobe、Sumatra、okular等)中打开文件,然后将其按Ctrl+A、Ctrl+C、Ctrl+V组合到记事本中,并将每一行以合理的格式对齐,这样我就可以运行正则表达式并将其复制粘贴到Excel中,以备以后需要 当我尝试用python实现这一点时,我尝试了各种模块,PDFminer是主要的模块,它通过使用。但它只返回一列中的数据。其他选项包括just,但在本例中,它添加了额外的拆分中间表,这

我有一个过程,我正在寻找自动化的环境从一个PDF文件获得一系列的表。目前,我可以通过在任何查看器(Adobe、Sumatra、okular等)中打开文件,然后将其按Ctrl+A、Ctrl+C、Ctrl+V组合到记事本中,并将每一行以合理的格式对齐,这样我就可以运行正则表达式并将其复制粘贴到Excel中,以备以后需要

当我尝试用python实现这一点时,我尝试了各种模块,PDFminer是主要的模块,它通过使用。但它只返回一列中的数据。其他选项包括just,但在本例中,它添加了额外的拆分中间表,这使得解析更加复杂,甚至偶尔在第一页和第二页之间切换列

我现在已经有了一个临时解决方案,但是我担心我正在重新发明轮子,因为我可能只是在解析器中缺少了一个核心选项,或者我需要考虑PDF渲染器工作的一些基本选项来解决这个问题。


从如何处理这个问题上有什么想法吗?

我最终实现了一个基于的解决方案,它本身就是由一个代码修改而来的。到目前为止,它在我测试过的所有情况下都能持续工作,但我还没有确定如何直接操作pdfminer的参数以获得所需的行为。

发布此消息只是为了获得一段代码,该代码与py35一起用于类似csv的解析。列中的拆分是最简单的,但对我来说很有效

克鲁多斯以tgray在这方面为出发点

还加入了openpyxl,因为我更喜欢将结果直接放在excel中

# works with py35 & pip-installed pdfminer.six in 2017
def pdf_to_csv(filename):
    from io import StringIO
    from pdfminer.converter import LTChar, TextConverter
    from pdfminer.layout import LAParams
    from pdfminer.pdfdocument import PDFDocument
    from pdfminer.pdfpage import PDFPage
    from pdfminer.pdfparser import PDFParser
    from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter

    class CsvConverter(TextConverter):
        def __init__(self, *args, **kwargs):
            TextConverter.__init__(self, *args, **kwargs)

        def end_page(self, i):
            from collections import defaultdict
            lines = defaultdict(lambda : {})
            for child in self.cur_item._objs:
                if isinstance(child, LTChar):
                    (_,_,x,y) = child.bbox
                    line = lines[int(-y)]
                    line[x] = child.get_text()
                    # the line is now an unsorted dict

            for y in sorted(lines.keys()):
                line = lines[y]
                # combine close letters to form columns
                xpos = tuple(sorted(line.keys()))
                new_line = []
                temp_text = ''
                for i in range(len(xpos)-1):
                    temp_text += line[xpos[i]]
                    if xpos[i+1] - xpos[i] > 8:
                        # the 8 is representing font-width
                        # needs adjustment for your specific pdf
                        new_line.append(temp_text)
                        temp_text = ''
                # adding the last column which also manually needs the last letter
                new_line.append(temp_text+line[xpos[-1]])

                self.outfp.write(";".join(nl for nl in new_line))
                self.outfp.write("\n")

    # ... the following part of the code is a remix of the 
    # convert() function in the pdfminer/tools/pdf2text module
    rsrc = PDFResourceManager()
    outfp = StringIO()
    device = CsvConverter(rsrc, outfp, codec="utf-8", laparams=LAParams())

    fp = open(filename, 'rb')
    parser = PDFParser(fp)
    doc = PDFDocument(parser)
    password = ""
    maxpages = 0
    caching = True
    pagenos=set()

    interpreter = PDFPageInterpreter(rsrc, device)

    for i, page in enumerate(PDFPage.get_pages(fp,
                                pagenos, maxpages=maxpages,
                                password=password,caching=caching,
                                check_extractable=True)):
        outfp.write("START PAGE %d\n" % i)
        if page is not None:
            interpreter.process_page(page)
        outfp.write("END PAGE %d\n" % i)

    device.close()
    fp.close()

    return outfp.getvalue()

fn = 'your_file.pdf'
result = pdf_to_csv(fn)

lines = result.split('\n')
import openpyxl as pxl
wb = pxl.Workbook()
ws = wb.active
for line in lines:
    ws.append(line.split(';'))
    # appending a list gives a complete row in xlsx
wb.save('your_file.xlsx')

您是否找到了使用pdfminer Python库来保持输出文本布局与PDF文档相同的解决方法/解决方案?查看源代码,有一种方法可以控制布局参数,但指定正确的值需要反复尝试。用法示例:。我想我将使用
pdftotext-layout input.pdf output.txt
,请参见:我确实发现它是正确的,但由于实现过于仓促,因此忘记提供答案。我会检查代码,几分钟后提供。