从布局与copy+pas相同的PDF文件中获取数据

2024-04-25 12:19:49 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个程序,我正在寻找自动化的环境,从一个PDF文件中获取一系列的表。目前,我可以通过在任何查看器(Adobe、Sumatra、okular等)中打开文件,只需按Ctrl+A、Ctrl+C、Ctrl+V将其放入记事本,然后我就可以运行regex并将其复制并粘贴到Excel中,以备以后需要的任何操作。在

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

我已经得到了一个暂时的解决方案,但我担心我会重新设计轮子,因为我可能只是缺少了解析器中的一个核心选项,或者我需要考虑PDF呈现器工作方式的一些基本选项来解决这个问题。在

有什么办法吗?在


Tags: 模块文件程序环境pdf粘贴选项excel
2条回答

发布这篇文章只是为了得到一段代码,可以与py35一起进行csv类解析。分栏是最简单的方法,但对我有效。在

将此answer中的tgray作为起点。在

另外,由于我更喜欢将结果直接放在excel中,所以也将其放在openpyxl中。在

# 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')

我最终实现了一个基于this one的解决方案,它本身是由tgray修改的代码。到目前为止,在我测试过的所有案例中,它都是一致的,但是我还没有确定如何直接操作pdfminer的参数以获得所需的行为。在

相关问题 更多 >

    热门问题