it-swarm.com.de

Wie extrahiere ich Text aus einer PDF Datei?

Ich versuche, den in this PDF enthaltenen Text mit Python zu extrahieren.

Ich benutze das PyPDF2 Modul und habe das folgende Skript:

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

Wenn ich den Code ausführe, erhalte ich die folgende Ausgabe, die sich von der im Dokument PDF enthaltenen unterscheidet:

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

Wie kann ich den Text so extrahieren, wie er im Dokument PDF enthalten ist?

119
Simplicity

War auf der Suche nach einer einfachen Lösung für python 3.x und Windows. Es scheint keine Unterstützung von textract zu geben, was bedauerlich ist, aber wenn Sie nach einer einfachen Lösung für Windows/Python 3 suchen, lesen Sie das tika -Paket Vorwärts zum Lesen von PDFs

from tika import parser

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

Verwenden Sie Textract.

Es unterstützt viele Arten von Dateien, einschließlich PDFs

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

Schau dir diesen Code an:

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

Die Ausgabe ist:

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

Verwenden des gleichen Codes zum Lesen eines PDFs aus 201308FCR.pdf . Die Ausgabe ist normal.

Seine Dokumentation erklärt, warum:

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.
    """
40
Quinn

Nachdem ich versucht hatte, textract (das zu viele Abhängigkeiten zu haben schien) und pypdf2 (das keinen Text aus den von mir getesteten pdfs extrahieren konnte) und tika (das zu langsam war), verwendete ich pdftotext aus xpdf (wie bereits vorgeschlagen) in einer anderen Antwort) und haben gerade die Binärdatei von python direkt aufgerufen (möglicherweise müssen Sie den Pfad an pdftotext anpassen):

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

Es gibt pdftotext , das im Prinzip dasselbe tut, aber dies setzt pdftotext in/usr/local/bin voraus, während ich dies in AWS Lambda verwende und es aus dem aktuellen Verzeichnis verwenden wollte.

Btw: Um dies für Lambda zu verwenden, müssen Sie die Binärdatei und die Abhängigkeit von libstdc++.so in Ihre Lambda-Funktion einfügen. Ich persönlich musste xpdf kompilieren. Als Anleitung dafür würde diese Antwort in die Luft jagen ich sie auf meinem persönlichen Blog .

20
hansaplast

Möglicherweise möchten Sie bewährte xPDF und abgeleitete Tools zum Extrahieren von Text verwenden, da pyPDF2 verschiedene Probleme mit der Textextrahierung immer noch zu haben scheint.

Die lange Antwort ist, dass es viele Variationen gibt, wie ein Text in PDF codiert wird und dass es möglicherweise erforderlich ist, PDF Zeichenfolgen selbst zu decodieren, und dass dann möglicherweise eine Zuordnung mit CMAP erforderlich ist Abstand zwischen Wörtern und Buchstaben etc. analysieren müssen.

Wenn das PDF beschädigt ist (dh wenn der richtige Text angezeigt wird, aber beim Kopieren Müll entsteht) und Sie wirklich Text extrahieren müssen, sollten Sie das PDF in ein Bild konvertieren ( Verwenden Sie ImageMagik ) und dann Tesseract , um mithilfe von OCR Text aus dem Bild abzurufen.

10
Eugene

Der folgende Code ist eine Lösung für die Frage in Python. Stellen Sie vor dem Ausführen des Codes sicher, dass Sie die Bibliothek PyPDF2 in Ihrer Umgebung installiert haben. Falls nicht installiert, öffnen Sie die Eingabeaufforderung und führen Sie den folgenden Befehl aus:

pip3 install PyPDF2

Lösungscode:

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())
7

Mehrseitige PDF-Dateien können als Text in einem Zug extrahiert werden, anstatt die einzelnen Seitenzahlen als Argument unter Verwendung des folgenden Codes anzugeben

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')
4
Yogi

Sie können PDFtoText https://github.com/jalan/pdftotext verwenden

PDF zu Text behält die Einrückung im Textformat bei, egal ob Tabellen vorhanden sind oder nicht.

3
Máxima Alekz

Ich habe viele Python PDF Konverter ausprobiert, Tika ist am besten.

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 )
2
erfelipe

Hier ist der einfachste Code zum Extrahieren von Text

code:

# 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()
2
Infinity

pdftotext ist der beste und einfachste! pdftotext behält auch die Struktur bei.

Ich habe PyPDF2, PDFMiner und einige andere ausprobiert, aber keiner von ihnen hat ein zufriedenstellendes Ergebnis geliefert.

2
Dharam

Ich habe hier eine Lösung gefunden PDFLayoutTextStripper

Es ist gut, weil es das Layout des Original-PDFs beibehalten kann .

Es ist in Java geschrieben, aber ich habe ein Gateway zur Unterstützung von Python hinzugefügt.

Beispielcode:

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']

Beispielausgabe von PDFLayoutTextStripper : enter image description here

Sie können mehr Details hier sehen Stripper mit Python

2
Tho

PyPDF2 ignoriert in einigen Fällen die Leerzeichen und macht den Ergebnistext zu einem Chaos, aber ich verwende PyMuPDF und bin sehr zufrieden, dass Sie dieses Link für weitere Informationen verwenden können

2
ehsaneha

Sie können tika-app-xxx.jar (aktuell) von hier herunterladen.

Legen Sie dann diese JAR-Datei im selben Ordner wie Ihre Skriptdatei python ab.

fügen Sie dann den folgenden Code in das Skript ein:

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

Der Vorteil dieser Methode:

weniger Abhängigkeit. Eine einzelne .jar-Datei ist einfacher zu verwalten als ein python -Paket.

Unterstützung für mehrere Formate. Die Position source_pdf kann das Verzeichnis jeder Art von Dokument sein. (.doc, .html, .odt usw.)

auf dem Laufenden. tika-app.jar wird immer früher als die entsprechende Version des Pakets tika python veröffentlicht.

stabil. Es ist weitaus stabiler und gepflegter (Powered by Apache) als PyPDF.

nachteil:

Ein Jre-Headless ist notwendig.

0
pah8J

PyPDF2 funktioniert, aber die Ergebnisse können variieren. Ich sehe ziemlich widersprüchliche Ergebnisse aus der Ergebnisextraktion.

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

Ich füge Code hinzu, um dies zu erreichen: Es funktioniert gut für mich:

# 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)
0
Ritesh Shanker

Wenn Sie es in Anaconda unter Windows versuchen, verarbeitet PyPDF2 möglicherweise einige PDF-Dateien mit nicht standardmäßigen Strukturen oder Unicode-Zeichen nicht. Ich empfehle den folgenden Code, wenn Sie viele PDF-Dateien öffnen und lesen müssen - der Text aller PDF-Dateien im Ordner mit dem relativen Pfad .//pdfs// wird in der Liste pdf_text_list gespeichert.

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)
0
Gibron