programing

PDF를 텍스트로 변환하기 위한 Python 모듈

prostudy 2022. 3. 25. 22:06
반응형

PDF를 텍스트로 변환하기 위한 Python 모듈

PDF 파일을 텍스트로 변환할 수 있는 파이선 모듈이 있는가?나는 pypdf를 사용하는 Activate에서 찾은 코드 한 조각을 시도해 보았지만 생성된 텍스트는 공백이 없고 쓸모가 없었다.

PDFMiner를 사용해 보십시오.PDF 파일에서 HTML, SGML 또는 "태그된 PDF" 형식으로 텍스트를 추출할 수 있다.

Tagged PDF 형식은 가장 깨끗한 것으로 보이며 XML 태그를 제거하면 맨 텍스트만 남는다.

다음에서 Python 3 버전을 사용할 수 있음:

PDFMiner 패키지는 코드테이프가 게시된 이후 변경되었다.

편집(again):

PDFMinerga에서 20100213

다음을 사용하여 설치한 버전을 확인할 수 있다.

>>> import pdfminer
>>> pdfminer.__version__
'20100213'

업데이트된 버전(변경/추가 항목에 대한 설명 포함)

def pdf_to_csv(filename):
    from cStringIO import StringIO  #<-- added so you can copy/paste this to try it
    from pdfminer.converter import LTTextItem, TextConverter
    from pdfminer.pdfparser import PDFDocument, 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, LTTextItem):
                    (_,_,x,y) = child.bbox                   #<-- changed
                    line = lines[int(-y)]
                    line[x] = child.text.encode(self.codec)  #<-- changed

            for y in sorted(lines.keys()):
                line = lines[y]
                self.outfp.write(";".join(line[x] for x in sorted(line.keys())))
                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")  #<-- changed 
        # becuase my test documents are utf-8 (note: utf-8 is the default codec)

    doc = PDFDocument()
    fp = open(filename, 'rb')
    parser = PDFParser(fp)       #<-- changed
    parser.set_document(doc)     #<-- added
    doc.set_parser(parser)       #<-- added
    doc.initialize('')

    interpreter = PDFPageInterpreter(rsrc, device)

    for i, page in enumerate(doc.get_pages()):
        outfp.write("START PAGE %d\n" % i)
        interpreter.process_page(page)
        outfp.write("END PAGE %d\n" % i)

    device.close()
    fp.close()

    return outfp.getvalue()

편집(다시 한 번):

여기 최신 버전의 pypi 업데이트 입니다.20100619p1간단히 말해서 나는 교체했다.LTTextItem와 함께LTChar그리고 LAParams의 인스턴스를 CsvConverter 생성자에게 전달하였다.

def pdf_to_csv(filename):
    from cStringIO import StringIO  
    from pdfminer.converter import LTChar, TextConverter    #<-- changed
    from pdfminer.layout import LAParams
    from pdfminer.pdfparser import PDFDocument, 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):               #<-- changed
                    (_,_,x,y) = child.bbox                   
                    line = lines[int(-y)]
                    line[x] = child.text.encode(self.codec)

            for y in sorted(lines.keys()):
                line = lines[y]
                self.outfp.write(";".join(line[x] for x in sorted(line.keys())))
                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())  #<-- changed
        # becuase my test documents are utf-8 (note: utf-8 is the default codec)

    doc = PDFDocument()
    fp = open(filename, 'rb')
    parser = PDFParser(fp)       
    parser.set_document(doc)     
    doc.set_parser(parser)       
    doc.initialize('')

    interpreter = PDFPageInterpreter(rsrc, device)

    for i, page in enumerate(doc.get_pages()):
        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()

편집(한 번 더):

버전에 대해 업데이트됨20110515(오우에프코케 펜테아노 덕분에!):

def pdf_to_csv(filename):
    from cStringIO import StringIO  
    from pdfminer.converter import LTChar, TextConverter
    from pdfminer.layout import LAParams
    from pdfminer.pdfparser import PDFDocument, 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:                #<-- changed
                if isinstance(child, LTChar):
                    (_,_,x,y) = child.bbox                   
                    line = lines[int(-y)]
                    line[x] = child._text.encode(self.codec) #<-- changed

            for y in sorted(lines.keys()):
                line = lines[y]
                self.outfp.write(";".join(line[x] for x in sorted(line.keys())))
                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())
        # becuase my test documents are utf-8 (note: utf-8 is the default codec)

    doc = PDFDocument()
    fp = open(filename, 'rb')
    parser = PDFParser(fp)       
    parser.set_document(doc)     
    doc.set_parser(parser)       
    doc.initialize('')

    interpreter = PDFPageInterpreter(rsrc, device)

    for i, page in enumerate(doc.get_pages()):
        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()

이러한 솔루션에는 최신 버전의 PDFMiner를 지원하지 않기 때문에 PDFMiner를 사용하여 PDF 텍스트를 반환하는 간단한 솔루션을 작성했다.이것은 수입 오류가 있는 사람들에게 효과가 있을 것이다.process_pdf

import sys
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.pdfpage import PDFPage
from pdfminer.converter import XMLConverter, HTMLConverter, TextConverter
from pdfminer.layout import LAParams
from cStringIO import StringIO

def pdfparser(data):

    fp = file(data, 'rb')
    rsrcmgr = PDFResourceManager()
    retstr = StringIO()
    codec = 'utf-8'
    laparams = LAParams()
    device = TextConverter(rsrcmgr, retstr, codec=codec, laparams=laparams)
    # Create a PDF interpreter object.
    interpreter = PDFPageInterpreter(rsrcmgr, device)
    # Process each page contained in the document.

    for page in PDFPage.get_pages(fp):
        interpreter.process_page(page)
        data =  retstr.getvalue()

    print data

if __name__ == '__main__':
    pdfparser(sys.argv[1])  

Python 3에 사용할 수 있는 아래 코드를 참조하십시오.

import sys
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.pdfpage import PDFPage
from pdfminer.converter import XMLConverter, HTMLConverter, TextConverter
from pdfminer.layout import LAParams
import io

def pdfparser(data):

    fp = open(data, 'rb')
    rsrcmgr = PDFResourceManager()
    retstr = io.StringIO()
    codec = 'utf-8'
    laparams = LAParams()
    device = TextConverter(rsrcmgr, retstr, codec=codec, laparams=laparams)
    # Create a PDF interpreter object.
    interpreter = PDFPageInterpreter(rsrcmgr, device)
    # Process each page contained in the document.

    for page in PDFPage.get_pages(fp):
        interpreter.process_page(page)
        data =  retstr.getvalue()

    print(data)

if __name__ == '__main__':
    pdfparser(sys.argv[1])  

Pdftotext 파이썬에서 호출할 수 있는 오픈 소스 프로그램(Xpdf의 일부)이다(요청한 것은 아니지만 유용할 수 있다).아무 문제 없이 사용해 보았다.구글이 구글 데스크톱에서 사용하는 것 같아.

PYPDF는 잘 작동한다(잘 구성된 PDF로 작업하고 있다고 가정).텍스트(공백 포함)만 원하는 경우:

import pyPdf
pdf = pyPdf.PdfFileReader(open(filename, "rb"))
for page in pdf.pages:
    print page.extractText()

메타데이터, 이미지 데이터 등에 쉽게 접근할 수 있다.

추출물에서 코멘트텍스트 코드 참고 사항:

내용 스트림에 제공된 순서대로 모든 텍스트 도면 명령을 찾아 텍스트를 추출하십시오.이는 일부 PDF 파일에는 잘 작동하지만, 사용된 제너레이터에 따라 다른 파일에는 잘 작동하지 않는다.이것은 장차 세련될 것이다.이 기능을 더 정교하게 만들면 변경되므로 이 기능에서 텍스트가 나오는 순서에 의존하지 마십시오.

이것이 문제인지 아닌지는 텍스트로 무엇을 하느냐에 따라 달라진다(예: 순서가 중요하지 않으면 괜찮거나, 생성기가 표시되는 순서대로 스트림에 텍스트를 추가하면 괜찮다).매일 사용하는 pyPdf 추출 코드가 있으며 문제 없음.

당신은 또한 꽤 쉽게 도서관으로 pdfminer를 사용할 수 있다.당신은 pdf의 컨텐츠 모델에 접근할 수 있으며, 당신만의 텍스트 추출물을 만들 수 있다.아래 코드를 사용하여 pdf 내용을 세미콜론 구분 텍스트로 변환하기 위해 이렇게 했다.

함수는 단순히 TextItem 내용 객체를 y 및 x 좌표에 따라 정렬하고, 동일한 y 좌표를 하나의 텍스트 라인으로 출력하여 ';' 문자로 동일한 라인에 있는 객체를 구분한다.

이 접근법을 사용하여 나는 pdf에서 다른 어떤 도구도 추가 구문 분석에 적합한 내용을 추출할 수 없는 텍스트를 추출할 수 있었다.다른 도구로는 pdftotext, ps2ascII, 온라인 도구 pdftextonline.com 등이 있다.

pdfminer는 pdf-proding에 매우 귀중한 도구다.


def pdf_to_csv(filename):
    from pdflib.page import TextItem, TextConverter
    from pdflib.pdfparser import PDFDocument, PDFParser
    from pdflib.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, TextItem):
                    (_,_,x,y) = child.bbox
                    line = lines[int(-y)]
                    line[x] = child.text

            for y in sorted(lines.keys()):
                line = lines[y]
                self.outfp.write(";".join(line[x] for x in sorted(line.keys())))
                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, "ascii")

    doc = PDFDocument()
    fp = open(filename, 'rb')
    parser = PDFParser(doc, fp)
    doc.initialize('')

    interpreter = PDFPageInterpreter(rsrc, device)

    for i, page in enumerate(doc.get_pages()):
        outfp.write("START PAGE %d\n" % i)
        interpreter.process_page(page)
        outfp.write("END PAGE %d\n" % i)

    device.close()
    fp.close()

    return outfp.getvalue()

업데이트:

위의 코드는 이전 버전의 API에 대해 작성되었으므로 아래 설명을 참조하십시오.

slate 라이브러리에서 PDFMiner를 매우 간단하게 사용할 수 있는 프로젝트:

>>> with open('example.pdf') as f:
...    doc = slate.PDF(f)
...
>>> doc
[..., ..., ...]
>>> doc[1]
'Text from page 2...'   

나는 특정 PDF를 파이선 모듈 내의 일반 텍스트로 변환해야 했다.나는 PDFMiner 20110515를 사용했는데, 그들의 pdf2txt.py 툴을 읽고 난 후 나는 다음과 같은 간단한 글을 썼다.

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

def to_txt(pdf_path):
    input_ = file(pdf_path, 'rb')
    output = StringIO()

    manager = PDFResourceManager()
    converter = TextConverter(manager, output, laparams=LAParams())
    process_pdf(manager, converter, input_)

    return output.getvalue() 

pdfminer와 함께 제공되는 pdf2txt.py 코드의 용도 변경. pdf의 경로를 이동하는 기능을 만들 수 있다. 선택적으로 아웃타입(txt|ft|xml|tag)을 선택하고 명령줄 pdf2txt {'-o': '/path/to/outfile'과 같은 옵션을 선택할 수 있다.txt' ...}. 기본적으로 다음을 호출할 수 있다.

convert_pdf(path)

원본 pdf에 파일 시스템에 형제인 텍스트 파일이 생성된다.

def convert_pdf(path, outtype='txt', opts={}):
    import sys
    from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter, process_pdf
    from pdfminer.converter import XMLConverter, HTMLConverter, TextConverter, TagExtractor
    from pdfminer.layout import LAParams
    from pdfminer.pdfparser import PDFDocument, PDFParser
    from pdfminer.pdfdevice import PDFDevice
    from pdfminer.cmapdb import CMapDB

    outfile = path[:-3] + outtype
    outdir = '/'.join(path.split('/')[:-1])

    debug = 0
    # input option
    password = ''
    pagenos = set()
    maxpages = 0
    # output option
    codec = 'utf-8'
    pageno = 1
    scale = 1
    showpageno = True
    laparams = LAParams()
    for (k, v) in opts:
        if k == '-d': debug += 1
        elif k == '-p': pagenos.update( int(x)-1 for x in v.split(',') )
        elif k == '-m': maxpages = int(v)
        elif k == '-P': password = v
        elif k == '-o': outfile = v
        elif k == '-n': laparams = None
        elif k == '-A': laparams.all_texts = True
        elif k == '-D': laparams.writing_mode = v
        elif k == '-M': laparams.char_margin = float(v)
        elif k == '-L': laparams.line_margin = float(v)
        elif k == '-W': laparams.word_margin = float(v)
        elif k == '-O': outdir = v
        elif k == '-t': outtype = v
        elif k == '-c': codec = v
        elif k == '-s': scale = float(v)
    #
    CMapDB.debug = debug
    PDFResourceManager.debug = debug
    PDFDocument.debug = debug
    PDFParser.debug = debug
    PDFPageInterpreter.debug = debug
    PDFDevice.debug = debug
    #
    rsrcmgr = PDFResourceManager()
    if not outtype:
        outtype = 'txt'
        if outfile:
            if outfile.endswith('.htm') or outfile.endswith('.html'):
                outtype = 'html'
            elif outfile.endswith('.xml'):
                outtype = 'xml'
            elif outfile.endswith('.tag'):
                outtype = 'tag'
    if outfile:
        outfp = file(outfile, 'w')
    else:
        outfp = sys.stdout
    if outtype == 'txt':
        device = TextConverter(rsrcmgr, outfp, codec=codec, laparams=laparams)
    elif outtype == 'xml':
        device = XMLConverter(rsrcmgr, outfp, codec=codec, laparams=laparams, outdir=outdir)
    elif outtype == 'html':
        device = HTMLConverter(rsrcmgr, outfp, codec=codec, scale=scale, laparams=laparams, outdir=outdir)
    elif outtype == 'tag':
        device = TagExtractor(rsrcmgr, outfp, codec=codec)
    else:
        return usage()

    fp = file(path, 'rb')
    process_pdf(rsrcmgr, device, fp, pagenos, maxpages=maxpages, password=password)
    fp.close()
    device.close()

    outfp.close()
    return

PDF miner는 내가 사용해 본 PDF 파일의 페이지마다 아마도 한 줄[7페이지 중 1페이지...]을 주었다.

내가 지금까지 가지고 있는 최고의 답은 pdftoipe, 또는 그것이 XPdf를 기반으로 한 c++ 코드다.

pdftoipe의 결과물이 어떻게 생겼는지 내 질문을 보라.

또한 Python에서 사용할 수 있는 상업용 Java 라이브러리인 PDFtextStream도 있다.

나는 사용해 왔다.pdftohtml…과 함께-xml논쟁, 결과를 읽어보십시오.subprocess.Popen()pdf에 있는 모든 텍스트 조각의 x 좌표, y 좌표, 너비, 높이 및 글꼴을 제공한다.나는 같은 오류 메시지가 분출되기 때문에 'evince'도 아마 이것을 사용하고 있을 것이라고 생각한다.

칼럼니스트 데이터를 처리해야 할 경우 pdf 파일에 맞는 알고리즘을 개발해야 하기 때문에 다소 복잡해진다.문제는 PDF 파일을 만드는 프로그램이 실제로 어떤 논리적인 형식으로도 텍스트를 배치하지 않는다는 점이다.간단한 분류 알고리즘을 시도해 볼 수도 있고 때로는 효과가 있지만, 생각했던 순서대로 입력되지 않는 '스트래글러'와 '스트레이즈'가 거의 없을 수 있다.그러니 창의력을 발휘해야 한다.

내가 작업하고 있던 pdf의 하나를 알아내는 데 약 5시간이 걸렸다.하지만 지금은 꽤 효과가 있다.행운을 빈다.

오늘 그 해결책을 찾았어.나한텐 잘된 일이지PDF 페이지를 PNG 영상에 렌더링.http://www.swftools.org/gfx_tutorial.html

참조URL: https://stackoverflow.com/questions/25665/python-module-for-converting-pdf-to-text

반응형