2016-11-26 17 views
2

PDF 파일에서 일련의 테이블을 가져 오는 과정을 자동화하는 절차가 있습니다. 현재 나는 어떤 뷰어 (Adobe, Sumatra, okular 등)에서 파일을 열고 Ctrl + A, Ctrl + C, Ctrl + V로 메모장에 파일을 열어서 그렇게 할 수 있으며, 각 라인을 합리적인 것으로 정렬합니다. 그 다음에 정규 표현식을 실행하고 나중에 필요할 때마다 Excel에 복사하여 붙여 넣을 수있는 충분한 형식입니다.복사 + 붙여 넣기와 같은 레이아웃으로 PDF 파일에서 데이터 가져 오기

파이썬에서이 작업을 시도 할 때, 다양한 모듈을 시도해 보았습니다. 어떤 종류의 코드가 this example for instance을 사용하여 가장 많이 사용되었습니다. 그러나 단일 열에 데이터를 반환합니다. 다른 옵션으로는 getting it as an html table 만 포함되지만이 경우 중간 분할 표가 추가되어 구문 분석이 복잡해 지거나 가끔 첫 번째 페이지와 두 번째 페이지 사이에서 열을 전환 할 수도 있습니다.

지금 임시 솔루션을 사용하고 있지만 파서의 핵심 옵션이 누락되었거나 휠체어의 기본 옵션을 고려해야 할 때 바퀴가 새롭게 등장 할까봐 걱정됩니다. PDF 렌더러가이를 해결하기 위해 노력합니다.

접근 방법에 대한 아이디어가 있습니까?

+0

pdfminer 파이썬 라이브러리를 사용하여 출력 텍스트의 레이아웃을 PDF 문서와 동일하게 유지하는 해결책을 찾았습니까? 소스 코드를 보면 레이아웃 매개 변수를 제어 할 수 있지만 올바른 값을 지정할 수있는 [LAParams 클래스] (https://github.com/goulu/pdfminer/blob/master/pdfminer/layout.py#L32)가 있습니다. 시행 착오입니다. 사용 예 : [extract_text_to_fp] (https://github.com/goulu/pdfminer/blob/master/pdfminer/high_level.py#L21). 나는'pdftotext -layout input.pdf output.txt'을 사용할 것이라고 생각합니다. http://askubuntu.com/q/52040 – bitek

+0

나는 그것을 찾았지만 돌격 때문에 답을 제공하는 것을 잊어 버렸습니다. 구현시. 코드를 확인하고 몇 분 후에 제공 할 것입니다. – Drexer

답변

1

코드가 tgray 인 것으로 수정 된 this one을 기반으로 솔루션을 구현했습니다. 지금까지 테스트 한 모든 경우에 일관되게 작동하지만 아직 원하는 동작을 얻으려면 pdfminer의 매개 변수를 직접 조작하는 방법을 식별해야합니다.

1

이 코드를 게시하면 csv와 유사한 구문 분석을 위해 py35와 함께 작동하는 코드 조각을 얻을 수 있습니다. 열의 분할은 가능한 가장 단순하지만 나를 위해 일했습니다.

tgray의 crudos는 answer을 시작으로 사용합니다.

또한 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')