Dans la série des types de documents nous avons vu entres autre les fichiers structurés au format YAML. Mais qu’en est-il de l’un des formats de fichier texte les plus courant : le pdf ? comment récupérer les données de ce format semi-structuré et ce bien sur en toute simplicité ? Bien sur si vous tapez dans Google Python et pdf vous trouverez plusieurs librairies candidates pour manipuler ces fichier. Nous allons voir ensemble et dans ce court article comment utiliser l’une d’elle pyPDF2.
Index
Qu’est-ce que pyPDF2 ?
PyPDF2 est une librairie Python trés utilisée permettant la lecture et quelques manipulations de fichiers au format pdf. Cette librairie est elle-même issue du projet pyPdf. Cette librairie est actuellement maintenue par Phaseit, Inc. et permet l’extraction des données provenant de fichiers PDF ou alors tout simplement manipuler des PDF existants dans l’idée de produire un nouveau fichier pdf (concaténation, filtrage de page, etc.). PyPDF2 est compatible avec les versions 2.6, 2.7 et 3.2 – 3.5 de Python.
NB: Utilisant la version 3.7 je n’ai pas rencontré de soucis particuliers …
L’installation est simple via l’utilitaire pip :
pip install pypdf2
Ouvrir un fichier pdf
L’utilisation de la librairie est plutôt simple et repose sur deux objets principaux : l’un en lecture et l’autre en écriture de fichier pdf.
from PyPDF2 import PdfFileReader
from PyPDF2 import PdfFileWriter
Ensuite pour lire un fichier pdf, rien de plus simple, il suffit de l’ouvrir comme n’importe quel fichier en Python et d’utiliser l’objet PdfFileReader.
Nous allons dans le cadre de notre exemple lire un fichier très simple :
document = PdfFileReader(open(myFile, 'rb'))
Le fichier est maintenant ouvert, regardons les méta-données :
metadata = document.getDocumentInfo()
print (metadata)
{'/Author': 'Benoit Cayla',
'/Creator': 'Microsoft® Word pour Office\xa0365',
'/CreationDate': "D:20201110115707+01'00'",
'/ModDate': "D:20201110115707+01'00'",
'/Producer': 'Microsoft® Word pour Office\xa0365'}
On peut les récupérer aussi directement comme ceci :
author = metadata.author if metadata.author else u'Unknown'
title = metadata.title if metadata.title else myFile
subject = metadata.subject if metadata.subject else "No Subject"
print (author + "|" + title + "|" + subject)
Benoit Cayla|test.pdf|No Subject
D’autres méthodes permettent de récupérer des informations importantes comme le nombre de page :
print(document.getNumPages())
1
Récupération des champs interactifs :
fields = document.getFields()
Mais aussi :
- Le type d’affichage avec getPageLayout()
- Le mode d’affichage avec getPageMode()
N’hésitez pas à consulter la documentation ici.
Lire le contenu du fichier pdf
On lit le contenu bien sur après avoir ouvert le fichier pdf avec PdfFileReader. Il faut bien sur tenir aussi compte de la pagination, la lecture se faisant page par page :
pdftext = ""
for page in range(document.numPages):
pageObj = document.getPage(page)
pdftext += pageObj.extractText().replace('\n','')
Bonjour ceci est un test ! Benoit Cayla
Vous remarquerez dans la dernière ligne que je retire les retours chariots (\n) car il sont récupérés tels quels par l’interpréteur.
Vous pouvez aussi regarder le détail (hiérarchique) des données qui ont été récupérées en affichant l’objet. Ce n’est pas d’une grande utilité tel quel mais celà vous montre que tout le contenu et méta-contenu à bien été récupéré.
print(pageObj)
{'/Type': '/Page',
'/Parent': {'/Type': '/Pages',
'/Count': 3,
'/Kids': [IndirectObject(3, 0), IndirectObject(4, 0), IndirectObject(5, 0)]},
'/Resources': {'/Font': {'/F1': {'/Type': '/Font',
'/Subtype': '/TrueType',
'/Name': '/F1',
'/BaseFont': '/BCDEEE+Calibri',
'/Encoding': '/WinAnsiEncoding',
'/FontDescriptor': {'/Type': '/FontDescriptor',
'/FontName': '/BCDEEE+Calibri',
'/Flags': 32,
'/ItalicAngle': 0,
'/Ascent': 750,
'/Descent': -250,
'/CapHeight': 750,
'/AvgWidth': 521,
'/MaxWidth': 1743,
'/FontWeight': 400,
'/XHeight': 250,
'/StemV': 52,
'/FontBBox': [-503, -250, 1240, 750],
'/FontFile2': {'/Filter': '/FlateDecode', '/Length1': 93840}},
'/FirstChar': 32,
'/LastChar': 117,
'/Widths': [226,
0,
...
0,
525]}},
'/ExtGState': {'/GS7': {'/Type': '/ExtGState', '/BM': '/Normal', '/ca': 1},
'/GS8': {'/Type': '/ExtGState', '/BM': '/Normal', '/CA': 1}},
'/ProcSet': ['/PDF', '/Text', '/ImageB', '/ImageC', '/ImageI']},
'/MediaBox': [0, 0, 595.2, 841.92],
'/Contents': {'/Filter': '/FlateDecode'},
'/Group': {'/Type': '/Group', '/S': '/Transparency', '/CS': '/DeviceRGB'},
'/Tabs': '/S',
'/StructParents': 0}
Créons maintenant un nouveau fichier pdf
Dans cet exemple nous allons concaténer 3 fichiers pdf en un seul. Voici les 3 fichiers pdf que l’on va dans un premier temps ouvrir :
pdflist = ["test.pdf" , "test2.pdf", "test3.pdf"]
Une fois ouvert, nous créons un nouveau fichier pdf avec PdfFileWriter:
pdfWriter = PdfFileWriter()
for filename in pdflist:
pdfFileObj = open(filename,'rb')
pdfReader = PdfFileReader(pdfFileObj)
for pageNum in range(pdfReader.numPages):
pageObj = pdfReader.getPage(pageNum)
pdfWriter.addPage(pageObj)
pdfOutput = open('final.pdf', 'wb')
pdfWriter.write(pdfOutput)
pdfOutput.close()
Nous rajoutons simplement les pages des pdf existants dans le nouveau pdf.
Conclusion
Nous avons vu dans cet article comment et en toute simplicité on pouvait lire des données textuelles à partir d’un fichier pdf. Attention car nous sommes parti du principe que ces données étaient du « vrai » texte et non pas des images (scannées) de texte placées dans un pdf. Dans ce cas de figure, il faudrait alors extraire l’image du pdf puis ensuite utiliser un OCR tel que Tesseract. Pour celà je vous suggère de lire mon article ici.
Comme d’habitude vous trouverez les sources de cet article sur GitHub.
Ingénieur en informatique avec plus de 20 ans d’expérience dans la gestion et l’utilisation de données, Benoit CAYLA a mis son expertise au profit de projets très variés tels que l’intégration, la gouvernance, l’analyse, l’IA, la mise en place de MDM ou de solution PIM pour le compte de diverses entreprises spécialisées dans la donnée (dont IBM, Informatica et Tableau). Ces riches expériences l’ont naturellement conduit à intervenir dans des projets de plus grande envergure autour de la gestion et de la valorisation des données, et ce principalement dans des secteurs d’activités tels que l’industrie, la grande distribution, l’assurance et la finance. Également, passionné d’IA (Machine Learning, NLP et Deep Learning), l’auteur a rejoint Blue Prism en 2019 et travaille aujourd’hui en tant qu’expert data/IA et processus. Son sens pédagogique ainsi que son expertise l’ont aussi amené à animer un blog en français (datacorner.fr) ayant pour but de montrer comment comprendre, analyser et utiliser ses données le plus simplement possible.
Bonjour à tous,
Je suis actuellement sur un projet dans le domaine du Machine Learning, le but est de faire une classification supervisée sur un ensemble de données. Mes données sont un grand nombre de fichiers pdf , chaque fichier à une classe precise, le but est d’utiliser ces fichiers la comme jeu de données d’apprentissage afin de faire de la prediction de la classe sur de nouveaux fichiers.
Mon probléme c’est que je ne sais pas comment construire mon jeu de données d’entrainement vu que l’algrithme de classification doit s’entrainer sur le contenu de chaque fichier et dans mon data Frame d’entrainement j’ai la classe de chaque fichier et le nom du fichier en question. comment faire pour inclure le contenu de chaque fichier pdf dans mon Data Frame d’entrainement ?
Merci par avance pour vorte aide
Bonjour,
Si j’ai bien compris votre question, il n’y a pas vraiment de soucis en réalité. Dans votre phase (partie de code) d’entraînement vous allez lire votre dataframe (pour recuperer le nom de fichier) et immédiatement lire le contenu du fichier, pour en exploiter directement le contenu … pas réellement besoin en fait de constituer un nouveau dataframe avec les features + labels puisque vous allez le construire à la volée.
bonjour Monsieur,
je suis un directeur commercial qui vient de commencer et comme vous le savez le budget assez serrer , j’ai bien envie une gestion de mais dossier sur pc en PDF avec un numéros et un nom , a ce jour je ne trouve pas un logiciel qui me convient , j’ai demander a un amis qui travaille sur java et a ce jour toujours pas réponse pas grave .
on espérant avoir trouver une personne qui me comprend .
cordialement
M abdelatif
Bonjour Benoît,
Je reviens à la fouille de texte après quelques mois de développement web.
DataCorner est toujours aussi instructif et permet en quelques minutes de découvrir de nouvelles librairies, de nouveaux outils.
Merci pour ce travail partagé et longue vie à DataCorner.
J-L Moiny.
Merci à toi J-L et à tes encouragements, c’est en effet le but: partager tout simplement et librement 😉
Bonjour.
Merci beaucoup pour votre partage vous faites un bon travail.
Pour ma part, j’ai 500 fichiers pdf de plan en format A4 qu’il me faut transformer en format tabloïd.
Quelle bibliothèque python me conseillez vous ?
Merci d’avance.
Je n’ai pas de réponse évidente car il faudrait en savoir plus sur le contexte et sur les attentes en matière de temps de reponses, etc. D’ailleurs il faudra peut être plusoeurs librairies ? Sinon la librairie PyPDF2 est vraiment une bonne boite a outils pour pdf en python.
Bonjour,
J’ai un petit projet à faire.
J’ai 2 gros dossiers où j’ai dans l’un plus de 300 fichiers PDF de 6 pages, et dans l’autre autant (ou moins mais jamais plus) de fichiers PDF de 2 pages.
Mon but est de parcourir le contenu des fichiers des 2 dossiers et si je trouve la même référence, je dois les fusionner.
EX. je lis le premier fichier de mon 1er dossier et puis je parcours le second dossiers pour trouver la même référence dans le contenu des fichiers et si je trouve la même référence, je les fusionne et l’enregistre ailleurs. (précision, je ne peux pas travailler avec le nom du fichier car je n’ai pas de référence).
Est-ce réalisable avec pyPDF2 ?