IT박스

PDF 파일에서 텍스트를 추출하는 방법은 무엇입니까?

itboxs 2020. 7. 3. 20:40
반응형

PDF 파일에서 텍스트를 추출하는 방법은 무엇입니까?


사용 하여이 PDF 파일에 포함 된 텍스트를 추출하려고합니다 Python.

PyPDF2 모듈을 사용하고 있으며 다음 스크립트가 있습니다.

import PyPDF2
pdf_file = open('sample.pdf')
read_pdf = PyPDF2.PdfFileReader(pdf_file)
number_of_pages = read_pdf.getNumPages()
page = read_pdf.getPage(0)
page_content = page.extractText()
print page_content

코드를 실행하면 PDF 문서에 포함 된 것과 다른 다음 출력이 나타납니다.

!"#$%#$%&%$&'()*%+,-%./01'*23%4
5'%1$#26%3/%7/))/8%&)/26%8#3"%3"*%313/9#&)
%

PDF 문서에서 그대로 텍스트를 추출하려면 어떻게해야합니까?


python 3.x 및 windows에 사용할 간단한 솔루션을 찾고있었습니다. 불행히도 textract 에서의 지원이없는 것 같지만 Windows / Python 3에 대한 간단한 솔루션을 찾고 있다면 tika 패키지를 체크 아웃하십시오.

from tika import parser

raw = parser.from_file('sample.pdf')
print(raw['content'])

textract를 사용하십시오.

PDF를 포함한 여러 유형의 파일을 지원합니다

import textract
text = textract.process("path/to/file.extension")

이 코드를보십시오 :

import PyPDF2
pdf_file = open('sample.pdf', 'rb')
read_pdf = PyPDF2.PdfFileReader(pdf_file)
number_of_pages = read_pdf.getNumPages()
page = read_pdf.getPage(0)
page_content = page.extractText()
print page_content.encode('utf-8')

출력은 다음과 같습니다.

!"#$%#$%&%$&'()*%+,-%./01'*23%4
5'%1$#26%3/%7/))/8%&)/26%8#3"%3"*%313/9#&)
%

동일한 코드를 사용하여 201308FCR.pdf 에서 PDF를 읽습니다 . 출력은 정상입니다.

문서 는 이유를 설명합니다.

def extractText(self):
    """
    Locate all text drawing commands, in the order they are provided in the
    content stream, and extract the text.  This works well for some PDF
    files, but poorly for others, depending on the generator used.  This will
    be refined in the future.  Do not rely on the order of text coming out of
    this function, as it will change if this function is made more
    sophisticated.
    :return: a unicode string object.
    """

textract (너무 많은 의존성이있는 것처럼 보임)와 pypdf2 (내가 테스트 한 pdf에서 텍스트를 추출 할 수 없음)와 tika (너무 느림) pdftotext를 시도한 후 xpdf에서 이미 사용했습니다 (다른 답변에서 이미 제안 했음). 파이썬에서 바이너리를 직접 호출했습니다 (pdftotext의 경로를 조정해야 할 수도 있습니다).

import os, subprocess
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
args = ["/usr/local/bin/pdftotext",
        '-enc',
        'UTF-8',
        "{}/my-pdf.pdf".format(SCRIPT_DIR),
        '-']
res = subprocess.run(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output = res.stdout.decode('utf-8')

pdftotext 기본적으로 동일한 작업을 수행하지만 AWS 람다이를 사용하여 현재 디렉토리에서 사용하고 싶어하고있는 반면이 pdftotext에서 / usr / 지방 / 빈을 가정합니다.

Btw : 람다에서 이것을 사용하려면 바이너리와 의존성을 libstdc++.so람다 함수 에 넣어야합니다 . 개인적으로 xpdf를 컴파일해야했습니다. 이것에 대한 지침 이이 답변을 날려 버릴 수 있으므로 개인 블로그에 넣었습니다 .


pyPDF2가 여전히 텍스트 추출에 여러 가지 문제 가있는 것처럼 보이기 때문에 시간이 증명 된 xPDF 및 파생 도구를 사용 하여 텍스트를 추출 할 수 있습니다.

긴 대답은 텍스트가 PDF 내에서 인코딩되는 방식이 다양하고 PDF 문자열 자체를 디코딩해야 할 수도 있고 CMAP을 사용하여 매핑해야 할 수도 있고 단어와 문자 사이의 거리를 분석해야 할 수도 있다는 것입니다.

PDF가 손상된 경우 (즉, 올바른 텍스트를 표시하지만 복사 할 때 가비지가 발생 함) 실제로 텍스트를 추출해야하는 경우 PDF를 이미지로 변환 ( ImageMagik 사용 ) 한 다음 Tesseract사용 하여 이미지에서 텍스트를 가져 오는 것이 좋습니다 OCR 사용


아래 코드는 Python 3 의 질문에 대한 솔루션 입니다. 코드를 실행하기 전에 PyPDF2환경에 라이브러리를 설치했는지 확인하십시오 . 설치되지 않은 경우 명령 프롬프트를 열고 다음 명령을 실행하십시오.

pip3 install PyPDF2

솔루션 코드 :

import PyPDF2
pdfFileObject = open('sample.pdf', 'rb')
pdfReader = PyPDF2.PdfFileReader(pdfFileObject)
count = pdfReader.numPages
for i in range(count):
    page = pdfReader.getPage(i)
    print(page.extractText())

아래 코드를 사용하여 개별 페이지 번호를 인수로 제공하는 대신 여러 페이지로 된 PDF를 한 번에 텍스트로 추출 할 수 있습니다.

import PyPDF2
import collections
pdf_file = open('samples.pdf', 'rb')
read_pdf = PyPDF2.PdfFileReader(pdf_file)
number_of_pages = read_pdf.getNumPages()
c = collections.Counter(range(number_of_pages))
for i in c:
   page = read_pdf.getPage(i)
   page_content = page.extractText()
   print page_content.encode('utf-8')

PDFtoText https://github.com/jalan/pdftotext를 사용할 수 있습니다

PDF에서 텍스트로 텍스트 형식 들여 쓰기를 유지합니다. 테이블이 있는지는 중요하지 않습니다.


경우에 따라 PyPDF2는 공백을 무시하고 결과 텍스트를 엉망으로 만들지 만 PyMuPDF를 사용 하며 자세한 내용을 보려면 링크사용할 수 있다고 확신합니다.


많은 Python PDF 변환기를 사용해 보았습니다 .Tika가 가장 좋습니다.

from tika import parser

raw = parser.from_file("///Users/Documents/Textos/Texto1.pdf")
raw = str(raw)

safe_text = raw.encode('utf-8', errors='ignore')

safe_text = str(safe_text).replace("\n", "").replace("\\", "")
print('--- safe text ---' )
print( safe_text )

여기에서 해결책을 찾았습니다 .PDFLayoutTextStripper

원본 PDF의 레이아웃을 유지할 수 있기 때문에 좋습니다 .

Java로 작성되었지만 Python을 지원하기 위해 게이트웨이를 추가했습니다.

샘플 코드 :

from py4j.java_gateway import JavaGateway

gw = JavaGateway()
result = gw.entry_point.strip('samples/bus.pdf')

# result is a dict of {
#   'success': 'true' or 'false',
#   'payload': pdf file content if 'success' is 'true'
#   'error': error message if 'success' is 'false'
# }

print result['payload']

PDFLayoutTextStripper의 샘플 출력 : 여기에 이미지 설명을 입력하십시오

자세한 내용은 여기 스트리퍼 (파이썬 포함)


텍스트를 추출하는 가장 간단한 코드는 다음과 같습니다.

암호:

# importing required modules
import PyPDF2

# creating a pdf file object
pdfFileObj = open('filename.pdf', 'rb')

# creating a pdf reader object
pdfReader = PyPDF2.PdfFileReader(pdfFileObj)

# printing number of pages in pdf file
print(pdfReader.numPages)

# creating a page object
pageObj = pdfReader.getPage(5)

# extracting text from page
print(pageObj.extractText())

# closing the pdf file object
pdfFileObj.close()

pdftotext 는 가장 좋고 가장 간단한 것입니다! pdftotext는 또한 구조를 예약합니다.

PyPDF2, PDFMiner 및 기타 몇 가지를 시도했지만 그중 어느 것도 만족스러운 결과를 얻지 못했습니다.


이것을 달성하기 위해 코드를 추가하고 있습니다 : 그것은 나를 위해 잘 작동합니다 :

# This works in python 3
# required python packages
# tabula-py==1.0.0
# PyPDF2==1.26.0
# Pillow==4.0.0
# pdfminer.six==20170720

import os
import shutil
import warnings
from io import StringIO

import requests
import tabula
from PIL import Image
from PyPDF2 import PdfFileWriter, PdfFileReader
from pdfminer.converter import TextConverter
from pdfminer.layout import LAParams
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.pdfpage import PDFPage

warnings.filterwarnings("ignore")


def download_file(url):
    local_filename = url.split('/')[-1]
    local_filename = local_filename.replace("%20", "_")
    r = requests.get(url, stream=True)
    print(r)
    with open(local_filename, 'wb') as f:
        shutil.copyfileobj(r.raw, f)

    return local_filename


class PDFExtractor():
    def __init__(self, url):
        self.url = url

    # Downloading File in local
    def break_pdf(self, filename, start_page=-1, end_page=-1):
        pdf_reader = PdfFileReader(open(filename, "rb"))
        # Reading each pdf one by one
        total_pages = pdf_reader.numPages
        if start_page == -1:
            start_page = 0
        elif start_page < 1 or start_page > total_pages:
            return "Start Page Selection Is Wrong"
        else:
            start_page = start_page - 1

        if end_page == -1:
            end_page = total_pages
        elif end_page < 1 or end_page > total_pages - 1:
            return "End Page Selection Is Wrong"
        else:
            end_page = end_page

        for i in range(start_page, end_page):
            output = PdfFileWriter()
            output.addPage(pdf_reader.getPage(i))
            with open(str(i + 1) + "_" + filename, "wb") as outputStream:
                output.write(outputStream)

    def extract_text_algo_1(self, file):
        pdf_reader = PdfFileReader(open(file, 'rb'))
        # creating a page object
        pageObj = pdf_reader.getPage(0)

        # extracting extract_text from page
        text = pageObj.extractText()
        text = text.replace("\n", "").replace("\t", "")
        return text

    def extract_text_algo_2(self, file):
        pdfResourceManager = PDFResourceManager()
        retstr = StringIO()
        la_params = LAParams()
        device = TextConverter(pdfResourceManager, retstr, codec='utf-8', laparams=la_params)
        fp = open(file, 'rb')
        interpreter = PDFPageInterpreter(pdfResourceManager, device)
        password = ""
        max_pages = 0
        caching = True
        page_num = set()

        for page in PDFPage.get_pages(fp, page_num, maxpages=max_pages, password=password, caching=caching,
                                      check_extractable=True):
            interpreter.process_page(page)

        text = retstr.getvalue()
        text = text.replace("\t", "").replace("\n", "")

        fp.close()
        device.close()
        retstr.close()
        return text

    def extract_text(self, file):
        text1 = self.extract_text_algo_1(file)
        text2 = self.extract_text_algo_2(file)

        if len(text2) > len(str(text1)):
            return text2
        else:
            return text1

    def extarct_table(self, file):

        # Read pdf into DataFrame
        try:
            df = tabula.read_pdf(file, output_format="csv")
        except:
            print("Error Reading Table")
            return

        print("\nPrinting Table Content: \n", df)
        print("\nDone Printing Table Content\n")

    def tiff_header_for_CCITT(self, width, height, img_size, CCITT_group=4):
        tiff_header_struct = '<' + '2s' + 'h' + 'l' + 'h' + 'hhll' * 8 + 'h'
        return struct.pack(tiff_header_struct,
                           b'II',  # Byte order indication: Little indian
                           42,  # Version number (always 42)
                           8,  # Offset to first IFD
                           8,  # Number of tags in IFD
                           256, 4, 1, width,  # ImageWidth, LONG, 1, width
                           257, 4, 1, height,  # ImageLength, LONG, 1, lenght
                           258, 3, 1, 1,  # BitsPerSample, SHORT, 1, 1
                           259, 3, 1, CCITT_group,  # Compression, SHORT, 1, 4 = CCITT Group 4 fax encoding
                           262, 3, 1, 0,  # Threshholding, SHORT, 1, 0 = WhiteIsZero
                           273, 4, 1, struct.calcsize(tiff_header_struct),  # StripOffsets, LONG, 1, len of header
                           278, 4, 1, height,  # RowsPerStrip, LONG, 1, lenght
                           279, 4, 1, img_size,  # StripByteCounts, LONG, 1, size of extract_image
                           0  # last IFD
                           )

    def extract_image(self, filename):
        number = 1
        pdf_reader = PdfFileReader(open(filename, 'rb'))

        for i in range(0, pdf_reader.numPages):

            page = pdf_reader.getPage(i)

            try:
                xObject = page['/Resources']['/XObject'].getObject()
            except:
                print("No XObject Found")
                return

            for obj in xObject:

                try:

                    if xObject[obj]['/Subtype'] == '/Image':
                        size = (xObject[obj]['/Width'], xObject[obj]['/Height'])
                        data = xObject[obj]._data
                        if xObject[obj]['/ColorSpace'] == '/DeviceRGB':
                            mode = "RGB"
                        else:
                            mode = "P"

                        image_name = filename.split(".")[0] + str(number)

                        print(xObject[obj]['/Filter'])

                        if xObject[obj]['/Filter'] == '/FlateDecode':
                            data = xObject[obj].getData()
                            img = Image.frombytes(mode, size, data)
                            img.save(image_name + "_Flate.png")
                            # save_to_s3(imagename + "_Flate.png")
                            print("Image_Saved")

                            number += 1
                        elif xObject[obj]['/Filter'] == '/DCTDecode':
                            img = open(image_name + "_DCT.jpg", "wb")
                            img.write(data)
                            # save_to_s3(imagename + "_DCT.jpg")
                            img.close()
                            number += 1
                        elif xObject[obj]['/Filter'] == '/JPXDecode':
                            img = open(image_name + "_JPX.jp2", "wb")
                            img.write(data)
                            # save_to_s3(imagename + "_JPX.jp2")
                            img.close()
                            number += 1
                        elif xObject[obj]['/Filter'] == '/CCITTFaxDecode':
                            if xObject[obj]['/DecodeParms']['/K'] == -1:
                                CCITT_group = 4
                            else:
                                CCITT_group = 3
                            width = xObject[obj]['/Width']
                            height = xObject[obj]['/Height']
                            data = xObject[obj]._data  # sorry, getData() does not work for CCITTFaxDecode
                            img_size = len(data)
                            tiff_header = self.tiff_header_for_CCITT(width, height, img_size, CCITT_group)
                            img_name = image_name + '_CCITT.tiff'
                            with open(img_name, 'wb') as img_file:
                                img_file.write(tiff_header + data)

                            # save_to_s3(img_name)
                            number += 1
                except:
                    continue

        return number

    def read_pages(self, start_page=-1, end_page=-1):

        # Downloading file locally
        downloaded_file = download_file(self.url)
        print(downloaded_file)

        # breaking PDF into number of pages in diff pdf files
        self.break_pdf(downloaded_file, start_page, end_page)

        # creating a pdf reader object
        pdf_reader = PdfFileReader(open(downloaded_file, 'rb'))

        # Reading each pdf one by one
        total_pages = pdf_reader.numPages

        if start_page == -1:
            start_page = 0
        elif start_page < 1 or start_page > total_pages:
            return "Start Page Selection Is Wrong"
        else:
            start_page = start_page - 1

        if end_page == -1:
            end_page = total_pages
        elif end_page < 1 or end_page > total_pages - 1:
            return "End Page Selection Is Wrong"
        else:
            end_page = end_page

        for i in range(start_page, end_page):
            # creating a page based filename
            file = str(i + 1) + "_" + downloaded_file

            print("\nStarting to Read Page: ", i + 1, "\n -----------===-------------")

            file_text = self.extract_text(file)
            print(file_text)
            self.extract_image(file)

            self.extarct_table(file)
            os.remove(file)
            print("Stopped Reading Page: ", i + 1, "\n -----------===-------------")

        os.remove(downloaded_file)


# I have tested on these 3 pdf files
# url = "http://s3.amazonaws.com/NLP_Project/Original_Documents/Healthcare-January-2017.pdf"
url = "http://s3.amazonaws.com/NLP_Project/Original_Documents/Sample_Test.pdf"
# url = "http://s3.amazonaws.com/NLP_Project/Original_Documents/Sazerac_FS_2017_06_30%20Annual.pdf"
# creating the instance of class
pdf_extractor = PDFExtractor(url)

# Getting desired data out
pdf_extractor.read_pages(15, 23)

tika-app-xxx.jar (latest)는 Here 에서 다운로드 할 수 있습니다 .

그런 다음이 .jar 파일을 파이썬 스크립트 파일의 동일한 폴더에 넣으십시오.

그런 다음 스크립트에 다음 코드를 삽입하십시오.

import os
import os.path

tika_dir=os.path.join(os.path.dirname(__file__),'<tika-app-xxx>.jar')

def extract_pdf(source_pdf:str,target_txt:str):
    os.system('java -jar '+tika_dir+' -t {} > {}'.format(source_pdf,target_txt))

이 방법의 장점 :

더 적은 의존성. 단일 .jar 파일은 해당 파이썬 패키지를 관리하기가 더 쉽습니다.

다중 형식 지원. 위치 source_pdf는 모든 종류의 문서 디렉토리 일 수 있습니다. (.doc, .html, .odt 등)

최신 정보. tika-app.jar은 항상 관련 버전의 tika python 패키지보다 먼저 릴리스됩니다.

안정된. PyPDF보다 훨씬 안정적이고 잘 관리되어 있습니다 (Apache 제공).

불리:

jre-headless가 필요합니다.


Windows의 Anaconda에서 시도하면 PyPDF2가 비표준 구조 또는 유니 코드 문자가있는 일부 PDF를 처리하지 못할 수 있습니다. 많은 pdf 파일을 열고 읽어야 할 경우 다음 코드를 사용하는 것이 좋습니다. 상대 경로 .//pdfs//가있는 폴더의 모든 pdf 파일의 텍스트가 목록에 저장됩니다 pdf_text_list.

from tika import parser
import glob

def read_pdf(filename):
    text = parser.from_file(filename)
    return(text)


all_files = glob.glob(".\\pdfs\\*.pdf")
pdf_text_list=[]
for i,file in enumerate(all_files):
    text=read_pdf(file)
    pdf_text_list.append(text['content'])

print(pdf_text_list)

PyPDF2는 작동하지만 결과는 다를 수 있습니다. 결과 추출에서 일관되지 않은 결과가 나타납니다.

reader=PyPDF2.pdf.PdfFileReader(self._path)
eachPageText=[]
for i in range(0,reader.getNumPages()):
    pageText=reader.getPage(i).extractText()
    print(pageText)
    eachPageText.append(pageText)

참고 URL : https://stackoverflow.com/questions/34837707/how-to-extract-text-from-a-pdf-file

반응형