Text aus einer PDF-Datei mit PDFMiner in Python extrahieren?

86

Ich suche nach Dokumentationen oder Beispielen zum Extrahieren von Text aus einer PDF-Datei mit PDFMiner mit Python.

Es sieht so aus, als hätte PDFMiner seine API aktualisiert und alle relevanten Beispiele, die ich gefunden habe, enthalten veralteten Code (Klassen und Methoden haben sich geändert). Die Bibliotheken, die ich gefunden habe, um das Extrahieren von Text aus einer PDF-Datei zu vereinfachen, verwenden die alte PDFMiner-Syntax, daher bin ich mir nicht sicher, wie ich das tun soll.

So wie es ist, schaue ich nur auf den Quellcode, um zu sehen, ob ich es herausfinden kann.

DuckPuncher
quelle
1
Bitte überprüfen Sie stackoverflow.com/help/how-to-ask und stackoverflow.com/help/mcve und aktualisieren Sie Ihre Antwort, damit sie in einem besseren Format vorliegt und den Richtlinien entspricht.
Parker
Welche Python-Distribution verwenden Sie, 2.7.x oder 3.xx? Es ist zu beachten, dass der Autor ausdrücklichPDFminer angibt, dass dies mit Python 3.xx nicht funktioniert. Dies könnte der Grund sein, warum Sie importFehler erhalten. Sie sollten dies verwenden pdfminer3k, da dies der ständige Python 3-Import dieser Bibliothek ist.
NullDev
@ Nanashi, sorry, ich habe vergessen meine Python Version hinzuzufügen. Es ist 2.7, also ist das nicht das Problem. Ich habe den Quellcode durchgesehen und es sieht so aus, als hätten sie einige Dinge umstrukturiert, weshalb die Importe brechen. Ich kann auch keine Dokumentation für PDFMiner finden oder ich würde nur daran arbeiten :(
DuckPuncher
Ich habe gerade buchstäblich PDFminervon GitHub installiert und es importiert gut. Können Sie bitte Ihren Code und auch Ihren vollständigen Fehler-Traceback veröffentlichen?
NullDev
@Nanashi, Wie ich in meiner ursprünglichen Frage sagte, brechen die Bibliotheken, die auf PDFMiner angewiesen sind, vor Abschluss des Imports zusammen mit einem Beispiel, das ich finden kann. Dies ist kein PDFMiner-Problem. Ich suche nach einer Dokumentation oder einem Beispiel für die Verwendung von PDFMiner. Alles, was ich finden kann, verwendet eine alte Syntax für PDFMiner. Ich habe meine Frage aus Gründen der Klarheit bearbeitet. Ich denke, ich habe es verwirrender gemacht, als es sein musste. Das tut mir leid.
DuckPuncher

Antworten:

181

Hier ist ein Arbeitsbeispiel zum Extrahieren von Text aus einer PDF-Datei mit der aktuellen Version von PDFMiner (September 2016).

from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.converter import TextConverter
from pdfminer.layout import LAParams
from pdfminer.pdfpage import PDFPage
from io import StringIO

def convert_pdf_to_txt(path):
    rsrcmgr = PDFResourceManager()
    retstr = StringIO()
    codec = 'utf-8'
    laparams = LAParams()
    device = TextConverter(rsrcmgr, retstr, codec=codec, laparams=laparams)
    fp = open(path, 'rb')
    interpreter = PDFPageInterpreter(rsrcmgr, device)
    password = ""
    maxpages = 0
    caching = True
    pagenos=set()

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

    text = retstr.getvalue()

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

Die Struktur von PDFMiner wurde kürzlich geändert, daher sollte dies zum Extrahieren von Text aus den PDF-Dateien funktionieren.

Bearbeiten : Funktioniert noch ab dem 7. Juni 2018. Verifiziert in Python Version 3.x.

Bearbeiten: Die Lösung funktioniert mit Python 3.7 am 3. Oktober 2019. Ich habe die Python-Bibliothek verwendet pdfminer.six, die im November 2018 veröffentlicht wurde.

DuckPuncher
quelle
2
funktioniert gut, aber wie kann ich mit Leerzeichen in beispielsweise Namen umgehen? Angenommen, ich habe ein PDF, das 4 Spalten enthält, in denen ich Vor- und Nachnamen in einer Spalte habe. Jetzt wird es mit Vornamen in einer Zeile und Nachnamen in einer Zeile analysiert. Hier ist ein Beispiel docdro.id/rRyef3x
Deusdeorum
2
Derzeit wird ein Importfehler mit diesem Code angezeigt: ImportError: Kein Modul mit dem Namen 'pdfminer.pdfpage'
Jeffrey Swan
1
Vielen Dank, dass es unter Python v2.7.12 und Ubuntu 16.04 funktioniert. Es ist jedoch besser, das PDF-Dokument mit der Codierung utf-8 zu laden, da mein Beispiel-PDF einige Codierungsprobleme aufweist. Versuchen Sie dies nach der Codierung mit utf-8 und beheben Sie das Problem Ausgabe ... import sys reload(sys) sys.setdefaultencoding('utf-8')
sib10
2
@ DuckPuncher, funktioniert es jetzt noch? Ich hatte das zu ändern , file(path, 'rb')um `open (Pfad,‚rb‘) mine zur Arbeit zu kommen.
Craned
2
Arbeitet immer noch für Python3.7-Benutzer. Installiertes Paket pdfminer.six == 20181108. Die bisher beste Lösung für meinen Fall und ich habe zahlreiche Lösungen verglichen.
aze45sq6d
29

tolle Antwort von DuckPuncher, für Python3 stellen Sie sicher, dass Sie pdfminer2 installieren und tun:

import io

from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.converter import TextConverter
from pdfminer.layout import LAParams
from pdfminer.pdfpage import PDFPage


def convert_pdf_to_txt(path):
    rsrcmgr = PDFResourceManager()
    retstr = io.StringIO()
    codec = 'utf-8'
    laparams = LAParams()
    device = TextConverter(rsrcmgr, retstr, codec=codec, laparams=laparams)
    fp = open(path, 'rb')
    interpreter = PDFPageInterpreter(rsrcmgr, device)
    password = ""
    maxpages = 0
    caching = True
    pagenos = set()

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



    fp.close()
    device.close()
    text = retstr.getvalue()
    retstr.close()
    return text
Juan Isaza
quelle
1
Es funktioniert nicht für mich: ModuleNotFoundError: Kein Modul mit dem Namen 'pdfminer.pdfpage' Ich verwende Python 3.6
Atti
@Atti, nur für den Fall, stellen Sie sicher, dass Sie pdfminer2 installiert haben, da es ein anderes Paket pdfminer gibt (ich hasse das). Es funktioniert für die Version pdfminer2 == 20151206, wenn pip3 eingefroren wird.
Juan Isaza
5
danke, dass ich es irgendwann zum Laufen gebracht habe, ich habe pdfminer.six von conda forge installiert
Atti
8
Für Python 3 ist pdfminer.six das empfohlene Paket - github.com/pdfminer/pdfminer.six
Mike Driscoll
Ist das noch aktuell? Ich ImportError:
12

Dies funktioniert im Mai 2020 mit PDFminer 6 in Python3.

Paket installieren

$ pip install pdfminer.six

Paket importieren

from pdfminer.high_level import extract_text

Verwenden einer auf der Festplatte gespeicherten PDF-Datei

text = extract_text('report.pdf')

Oder alternativ:

with open('report.pdf','rb') as f:
    text = extract_text(open('report.pdf','rb'))

Verwenden von PDF bereits im Speicher

Befindet sich die PDF-Datei bereits im Speicher, z. B. wenn sie mit der Anforderungsbibliothek aus dem Web abgerufen wurde, kann sie mithilfe der ioBibliothek in einen Stream konvertiert werden :

import io

response = requests.get(url)
text = extract_text(io.BytesIO(response.content))

Leistung und Zuverlässigkeit im Vergleich zu PyPDF2

PDFminer.six funktioniert zuverlässiger als PyPDF2 (was bei bestimmten PDF-Typen fehlschlägt), insbesondere PDF-Version 1.7

Die Textextraktion mit PDFminer.six ist jedoch um den Faktor 6 erheblich langsamer als PyPDF2.

Ich habe die Textextraktion mit timeiteinem 15 "MBP (2018) zeitlich festgelegt, nur die Extraktionsfunktion (kein Öffnen von Dateien usw.) mit einem 10-seitigen PDF zeitlich festgelegt und die folgenden Ergebnisse erhalten:

PDFminer.six: 2.88 sec
PyPDF2:       0.45 sec

pdfminer.six hat auch eine enorme Stellfläche und erfordert pycryptodome, für das GCC und andere Dinge installiert werden müssen, um ein minimales Docker-Image für die Installation unter Alpine Linux von 80 MB auf 350 MB zu verschieben. PyPDF2 hat keine merklichen Auswirkungen auf die Speicherung.

Cornelius Roemer
quelle
8

Vollständige Offenlegung, ich bin einer der Betreuer von pdfminer.six.

Heutzutage gibt es mehrere APIs, mit denen Sie je nach Bedarf Text aus einem PDF extrahieren können. Hinter den Kulissen verwenden alle diese APIs dieselbe Logik zum Parsen und Analysieren des Layouts.

Befehlszeile

Wenn Sie nur einmal Text extrahieren möchten, können Sie das Befehlszeilentool pdf2txt.py verwenden:

$ pdf2txt.py example.pdf

High-Level-API

Wenn Sie Text mit Python extrahieren möchten, können Sie die übergeordnete API verwenden. Dieser Ansatz ist die ideale Lösung, wenn Sie Text programmgesteuert aus vielen PDF-Dateien extrahieren möchten.

from pdfminer.high_level import extract_text

text = extract_text('samples/simple1.pdf')

Composable api

Es gibt auch eine zusammensetzbare API, die viel Flexibilität beim Umgang mit den resultierenden Objekten bietet. Damit können Sie beispielsweise Ihren eigenen Layout-Algorithmus implementieren. Diese Methode wird in den anderen Antworten vorgeschlagen, aber ich würde dies nur empfehlen, wenn Sie das Verhalten von pdfminer.six anpassen müssen.

from io import StringIO

from pdfminer.converter import TextConverter
from pdfminer.layout import LAParams
from pdfminer.pdfdocument import PDFDocument
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.pdfpage import PDFPage
from pdfminer.pdfparser import PDFParser

output_string = StringIO()
with open('samples/simple1.pdf', 'rb') as in_file:
    parser = PDFParser(in_file)
    doc = PDFDocument(parser)
    rsrcmgr = PDFResourceManager()
    device = TextConverter(rsrcmgr, output_string, laparams=LAParams())
    interpreter = PDFPageInterpreter(rsrcmgr, device)
    for page in PDFPage.create_pages(doc):
        interpreter.process_page(page)

print(output_string.getvalue())
Pieter
quelle
0

Dieser Code wird mit pdfminer für Python 3 getestet (pdfminer-20191125)

from pdfminer.layout import LAParams
from pdfminer.converter import PDFPageAggregator
from pdfminer.pdfinterp import PDFResourceManager
from pdfminer.pdfinterp import PDFPageInterpreter
from pdfminer.pdfpage import PDFPage
from pdfminer.layout import LTTextBoxHorizontal

def parsedocument(document):
    # convert all horizontal text into a lines list (one entry per line)
    # document is a file stream
    lines = []
    rsrcmgr = PDFResourceManager()
    laparams = LAParams()
    device = PDFPageAggregator(rsrcmgr, laparams=laparams)
    interpreter = PDFPageInterpreter(rsrcmgr, device)
    for page in PDFPage.get_pages(document):
            interpreter.process_page(page)
            layout = device.get_result()
            for element in layout:
                if isinstance(element, LTTextBoxHorizontal):
                    lines.extend(element.get_text().splitlines())
    return lines
Brault Gilbert
quelle
Ich habe PDF-Dateien, die ich mit dem Nitro Pro-Tool konvertieren kann. Wenn ich jedoch versuche, dasselbe PDF mit dem hier angegebenen Code zu konvertieren, wird eine Ausgabe angezeigt, die darauf hinweist, dass ein Berechtigungsfehler vorliegt. Hier ist die Ausgabe: ('aus den SAGE Social Science-Sammlungen. Alle Rechte vorbehalten. \ N \ n \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c \ x0c ')
b00kgrrl
Was meinst du mit einem Dateistream?
Vincent
@ Vincent mit open (Datei, 'rb') als Stream: [...]
Rodrigo Formighieri
schaffen Sie es, diese Datei idealerweise als Tabelle / Pandas zu erhalten? groupe-psa.com/de/publication/monthly-world-sales-march-2020
Nono London