Lire un fichier pdf avec Python

Partager cet article

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.

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 :

Contenu du fichier pdf
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.

Partager cet article

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée.

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.