Extraire du texte d'un fichier PDF à l'aide de PDFMiner en python?

87

Je recherche de la documentation ou des exemples sur la façon d'extraire du texte d'un fichier PDF en utilisant PDFMiner avec Python.

Il semble que PDFMiner a mis à jour son API et que tous les exemples pertinents que j'ai trouvés contiennent du code obsolète (les classes et les méthodes ont changé). Les bibliothèques que j'ai trouvées qui facilitent l'extraction de texte à partir d'un fichier PDF utilisent l'ancienne syntaxe PDFMiner, donc je ne sais pas comment faire cela.

Dans l'état actuel des choses, je regarde juste le code source pour voir si je peux le comprendre.

CanardPuncher
la source
1
Veuillez consulter stackoverflow.com/help/how-to-ask et stackoverflow.com/help/mcve et mettre à jour votre réponse afin qu'elle soit dans un meilleur format et s'aligne sur les directives.
Parker
Quelle distribution de Python utilisez-vous, 2.7.x ou 3.xx? Il convient de noter que l'auteur a expliqué explicitement que PDFminercela ne fonctionne pas avec Python 3.xx Cela pourrait être la raison pour laquelle vous obtenez des importerreurs. Vous devriez utiliser pdfminer3ksi c'est le cas, car il s'agit de l'importation Python 3 permanente de ladite bibliothèque.
NullDev
@Nanashi, désolé, j'ai oublié d'ajouter ma version Python. C'est 2.7 donc ce n'est pas le problème. J'ai regardé à travers le code source et il semble qu'ils ont restructuré certaines choses, c'est pourquoi les importations sont interrompues. Je ne trouve aucune documentation pour PDFMiner non plus ou je travaillerais simplement
dessus
Je viens de m'installer littéralement PDFminerà partir de GitHub et il importe bien. Pouvez-vous publier votre code et publier également votre traçage complet des erreurs?
NullDev
@Nanashi, comme je l'ai dit dans ma question initiale, les bibliothèques qui reposent sur PDFMiner se cassent avant de terminer les importations avec tout exemple que je peux trouver. Ce n'est pas un problème PDFMiner. C'est moi qui cherche de la documentation ou un exemple d'utilisation de PDFMiner. Tout ce que je peux trouver utilise une ancienne syntaxe pour PDFMiner. Je suis allé de l'avant et j'ai édité ma question pour plus de clarté. Je pense que je l'ai rendu plus déroutant que nécessaire. Désolé pour ça.
DuckPuncher

Réponses:

182

Voici un exemple de travail d'extraction de texte à partir d'un fichier PDF à l'aide de la version actuelle de PDFMiner (septembre 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 structure de PDFMiner a changé récemment, donc cela devrait fonctionner pour extraire le texte des fichiers PDF.

Edit : toujours en activité depuis le 7 juin 2018. Vérifié en Python version 3.x

Edit: La solution fonctionne avec Python 3.7 au 3 octobre 2019. J'ai utilisé la bibliothèque Python pdfminer.six, publiée en novembre 2018.

CanardPuncher
la source
2
fonctionne bien, mais comment puis-je gérer les espaces dans les noms par exemple? supposons que j'ai un pdf qui contient 4 colonnes où j'ai le prénom et le nom dans une colonne, maintenant il est analysé avec le prénom sur une ligne et le nom sur une ligne, voici un exemple docdro.id/rRyef3x
Deusdeorum
2
Obtention actuelle d'une erreur d'importation avec ce code: ImportError: Aucun module nommé 'pdfminer.pdfpage'
Jeffrey Swan
1
Merci, cela fonctionne sur python v2.7.12 et sur ubuntu 16.04, bien qu'il soit préférable de charger le document pdf avec encodage utf-8, car mon exemple de pdf a un problème d'encodage alors essayez ceci après l'encodage avec utf-8 et il résout le issue ... import sys reload(sys) sys.setdefaultencoding('utf-8')
sib10
2
@DuckPuncher, ça marche encore maintenant? J'ai dû changer le file(path, 'rb')en `open (path, 'rb') pour que le mien fonctionne.
craned
2
Travaille toujours pour les utilisateurs de Python3.7. Installation du package pdfminer.six == 20181108. Meilleure solution à ce jour pour mon cas et j'ai comparé de nombreuses solutions.
aze45sq6d
29

excellente réponse de DuckPuncher, pour Python3, assurez-vous d'installer pdfminer2 et faites:

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
la source
1
Cela ne fonctionne pas pour moi: ModuleNotFoundError: Aucun module nommé 'pdfminer.pdfpage' J'utilise python 3.6
Atti
@Atti, juste au cas où, assurez-vous que pdfminer2 est installé, car il existe un autre package pdfminer (je déteste ça). Cela fonctionne pour la version pdfminer2 == 20151206 lors de l'exécution de pip3 freeze.
juan Isaza
5
merci je l'ai fait fonctionner finalement, j'ai installé pdfminer.six de conda forge
Atti
8
Pour Python 3, pdfminer.six est le package recommandé - github.com/pdfminer/pdfminer.six
Mike Driscoll
Est-ce toujours d'actualité. Je reçois le même ImportError:message
12

Cela fonctionne en mai 2020 en utilisant PDFminer six dans Python3.

Installation du package

$ pip install pdfminer.six

Importer le package

from pdfminer.high_level import extract_text

Utilisation d'un PDF enregistré sur disque

text = extract_text('report.pdf')

Ou bien:

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

Utilisation de PDF déjà en mémoire

Si le PDF est déjà en mémoire, par exemple s'il est récupéré sur le Web avec la bibliothèque de requêtes, il peut être converti en flux à l'aide de la iobibliothèque:

import io

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

Performances et fiabilité par rapport à PyPDF2

PDFminer.six fonctionne de manière plus fiable que PyPDF2 (qui échoue avec certains types de PDF), en particulier PDF version 1.7

Cependant, l'extraction de texte avec PDFminer.six est nettement plus lente que PyPDF2 d'un facteur 6.

J'ai chronométré l'extraction de texte avec timeitun MBP de 15 "(2018), en chronométrant uniquement la fonction d'extraction (pas d'ouverture de fichier, etc.) avec un PDF de 10 pages et j'ai obtenu les résultats suivants:

PDFminer.six: 2.88 sec
PyPDF2:       0.45 sec

pdfminer.six a également une empreinte énorme, nécessitant pycryptodome qui a besoin de GCC et d'autres éléments installés poussant une image docker d'installation minimale sur Alpine Linux de 80 Mo à 350 Mo. PyPDF2 n'a pas d'impact notable sur le stockage.

Cornelius Roemer
la source
9

Divulgation complète, je suis l'un des mainteneurs de pdfminer.six.

De nos jours, il existe plusieurs API pour extraire du texte d'un PDF, en fonction de vos besoins. Dans les coulisses, toutes ces API utilisent la même logique pour analyser et analyser la mise en page.

Ligne de commande

Si vous souhaitez extraire du texte une seule fois, vous pouvez utiliser l'outil de ligne de commande pdf2txt.py:

$ pdf2txt.py example.pdf

API de haut niveau

Si vous souhaitez extraire du texte avec Python, vous pouvez utiliser l'API de haut niveau. Cette approche est la solution idéale si vous souhaitez extraire du texte par programme à partir de nombreux PDF.

from pdfminer.high_level import extract_text

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

API composable

Il existe également une API composable qui offre une grande flexibilité dans la gestion des objets résultants. Par exemple, vous pouvez implémenter votre propre algorithme de mise en page en utilisant cela. Cette méthode est suggérée dans les autres réponses, mais je ne la recommanderais que lorsque vous avez besoin de personnaliser le comportement de 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('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
la source
0

ce code est testé avec pdfminer pour 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
Brault Gilbert
la source
J'ai des fichiers PDF que je peux convertir à l'aide de l'outil Nitro Pro. Lorsque j'essaye de convertir le même PDF en utilisant le code publié ici, cependant, j'obtiens une sortie qui suggère qu'il y a une erreur d'autorisations. Voici le résultat: ('des collections de sciences sociales SAGE. Tous droits réservés. \ 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
Que voulez-vous dire par un flux de fichiers?
Vincent
@Vincent avec open (file, 'rb') comme flux: [...]
Rodrigo Formighieri
parvenez-vous à obtenir ce fichier sous forme de table / pandas idéalement? groupe-psa.com/en/publication/monthly-world-sales-march-2020
Nono Londres