Estrarre testo da un file PDF utilizzando PDFMiner in Python?


89

Sto cercando documentazione o esempi su come estrarre testo da un file PDF utilizzando PDFMiner con Python.

Sembra che PDFMiner abbia aggiornato la sua API e tutti gli esempi rilevanti che ho trovato contengono codice obsoleto (classi e metodi sono cambiati). Le librerie che ho scoperto che semplificano il compito di estrarre il testo da un file PDF utilizzano la vecchia sintassi PDFMiner, quindi non sono sicuro di come farlo.

Così com'è, sto solo guardando il codice sorgente per vedere se riesco a capirlo.


1
Controlla stackoverflow.com/help/how-to-ask e stackoverflow.com/help/mcve e aggiorna la tua risposta in modo che sia in un formato migliore e in linea con le linee guida.
Parker

Quale distribuzione di Python stai usando, 2.7.xo 3.xx? Va notato che l'autore ha esplicitamente spiegato che PDFminernon funziona con Python 3.xx Questo potrebbe essere il motivo per cui ricevi importerrori. Dovresti usare in pdfminer3ktal caso, poiché è l'importazione Python 3 in piedi di detta libreria.
NullDev

@Nanashi, scusa, ho dimenticato di aggiungere la mia versione di Python. È 2.7 quindi non è questo il problema. Ho esaminato il codice sorgente e sembra che abbiano ristrutturato alcune cose, motivo per cui le importazioni si stanno interrompendo. Non riesco a trovare alcuna documentazione per PDFMiner o ci starei semplicemente lavorando :(
DuckPuncher

Ho appena letteralmente installato PDFminerda GitHub e importa bene. Puoi gentilmente pubblicare il tuo codice e pubblicare anche il tuo completo traccia degli errori?
NullDev

@Nanashi, come ho detto nella mia domanda originale, le librerie che si basano su PDFMiner si interrompono prima di terminare le importazioni insieme a qualsiasi esempio che riesco a trovare. Questo non è un problema di PDFMiner. Sono io che cerco documentazione o un esempio di come utilizzare PDFMiner. Tutto quello che riesco a trovare utilizza una vecchia sintassi per PDFMiner. Sono andato avanti e ho modificato la mia domanda per chiarezza. Penso di aver reso tutto più confuso di quanto avrebbe dovuto essere. Mi dispiace per quello.
DuckPuncher

Risposte:


184

Ecco un esempio funzionante di estrazione di testo da un file PDF utilizzando la versione corrente di PDFMiner (settembre 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

La struttura di PDFMiner è cambiata di recente, quindi dovrebbe funzionare per l'estrazione del testo dai file PDF.

Modifica : ancora funzionante a partire dal 7 giugno 2018. Verificato in Python versione 3.x

Modifica: la soluzione funziona con Python 3.7 al 3 ottobre 2019. Ho usato la libreria Python pdfminer.six, rilasciata a novembre 2018.


2
funziona bene, ma come posso gestire gli spazi ad esempio nei nomi? supponiamo di avere un pdf che contiene 4 colonne in cui ho il nome e il cognome in una colonna, ora viene analizzato con il nome in una riga e il cognome in una riga, ecco un esempio docdro.id/rRyef3x
Deusdeorum

2
Attualmente ricevo un errore di importazione con questo codice: ImportError: Nessun modulo denominato "pdfminer.pdfpage"
Jeffrey Swan,

1
Grazie funziona su python v2.7.12 e su ubuntu 16.04, anche se sarebbe meglio caricare il documento pdf con la codifica utf-8, perché il mio pdf di esempio ha qualche problema di codifica quindi prova questo dopo la codifica con utf-8 e risolve il problema ... import sys reload(sys) sys.setdefaultencoding('utf-8')
sib10

2
@DuckPuncher, funziona ancora adesso? Ho dovuto cambiare file(path, 'rb')in `open (path, 'rb') per far funzionare il mio.
gru

2
Ancora funzionante per gli utenti di Python3.7. Pacchetto pdfminer.six == 20181108 installato. La migliore soluzione finora per il mio caso e ho confrontato numerose soluzioni.
aze45sq6d

30

ottima risposta da DuckPuncher, per Python3 assicurati di installare pdfminer2 e di fare:

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

1
Non funziona per me: ModuleNotFoundError: Nessun modulo denominato 'pdfminer.pdfpage' sto usando python 3.6
Atti

@ Atti, per ogni evenienza, assicurati di avere pdfminer2 installato, poiché c'è un altro pacchetto pdfminer (lo odio). Funziona per la versione pdfminer2 == 20151206 quando si esegue il blocco di pip3.
juan Isaza

5
grazie ho fatto funzionare alla fine, ho installato pdfminer.six da conda forge
Atti

8
Per Python 3, pdfminer.six è il pacchetto consigliato - github.com/pdfminer/pdfminer.six
Mike Driscoll

È ancora attuale. Ricevo lo stesso ImportError:messaggio

14

Funziona a maggio 2020 utilizzando PDFminer six in Python3.

Installazione del pacchetto

$ pip install pdfminer.six

Importazione del pacchetto

from pdfminer.high_level import extract_text

Utilizzando un PDF salvato su disco

text = extract_text('report.pdf')

Oppure in alternativa:

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

Utilizzo di PDF già in memoria

Se il PDF è già in memoria, ad esempio se recuperato dal web con la libreria delle richieste, può essere convertito in flusso utilizzando la iolibreria:

import io

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

Prestazioni e affidabilità rispetto a PyPDF2

PDFminer.six funziona in modo più affidabile di PyPDF2 (che fallisce con alcuni tipi di PDF), in particolare PDF versione 1.7

Tuttavia, l'estrazione del testo con PDFminer.six è significativamente più lenta di PyPDF2 di un fattore 6.

Ho cronometrato l'estrazione del testo con timeitun MBP da 15 "(2018), cronometrando solo la funzione di estrazione (nessuna apertura di file ecc.) Con un PDF di 10 pagine e ho ottenuto i seguenti risultati:

PDFminer.six: 2.88 sec
PyPDF2:       0.45 sec

pdfminer.six ha anche un ingombro enorme, che richiede pycryptodome che richiede GCC e altre cose installate spingendo un'immagine docker di installazione minima su Alpine Linux da 80 MB a 350 MB. PyPDF2 non ha alcun impatto notevole sullo storage.


Questo approccio potrebbe essere stato interrotto dall'ultimo aggiornamento. Attualmente ImportError: cannot import name 'open_filename' from 'pdfminer.utils'ricevo l'errore quando eseguofrom pdfminer.high_level import extract_text
Ulteriori letture

1
Aggiornamento: ho risolto questo problema creando un nuovo venv e reinstallando pdfminer.six. Immagino che uno degli altri pacchetti pdf che ho provato prima stesse interferendo in qualche modo.
Ulteriore lettura

11

Informativa completa, sono uno dei manutentori di pdfminer.six.

Al giorno d'oggi, ci sono più API per estrarre il testo da un PDF, a seconda delle tue esigenze. Dietro le quinte, tutte queste API utilizzano la stessa logica per analizzare e analizzare il layout.

(Tutti gli esempi presumono che il tuo file PDF si chiami example.pdf )

Riga di comando

Se desideri estrarre il testo una sola volta, puoi utilizzare lo strumento a riga di comando pdf2txt.py:

$ pdf2txt.py example.pdf

API di alto livello

Se vuoi estrarre del testo con Python, puoi usare l'api di alto livello. Questo approccio è la soluzione ideale se desideri estrarre il testo in modo programmatico da molti PDF.

from pdfminer.high_level import extract_text

text = extract_text('example.pdf')

API componibile

C'è anche un'API componibile che offre molta flessibilità nella gestione degli oggetti risultanti. Ad esempio, puoi implementare il tuo algoritmo di layout usando quello. Questo metodo è suggerito nelle altre risposte, ma lo consiglierei solo quando è necessario personalizzare il modo in cui si comporta pdfminer.six.

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('example.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())

0

questo codice è stato testato con pdfminer per python 3 (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

Ho file PDF che posso convertire utilizzando lo strumento Nitro Pro. Quando provo a convertire lo stesso PDF utilizzando il codice pubblicato qui, tuttavia, ottengo un output che suggerisce che c'è un errore di autorizzazione. Ecco l'output: ('dalle raccolte di scienze sociali di SAGE. Tutti i diritti riservati. \ 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

Cosa intendi per flusso di file?
Vincent

@Vincent con open (file, 'rb') come stream: [...]
Rodrigo Formighieri

riesci a ottenere questo file come tabella / panda idealmente? groupe-psa.com/en/publication/monthly-world-sales-march-2020
Nono London,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.