[PYTHON] Examinez s'il s'agit d'un PDF et du traitement des exceptions Jusqu'à ce que vous créiez votre propre traitement des exceptions

"Création d'un service qui modifie l'historique d'utilisation de Suica mobile afin qu'il puisse être facilement utilisé pour le règlement des dépenses" Transformez le fichier PDF de l'historique d'utilisation de Suica mobile au format pandas DataFrame avec tabula-py Cliquez ici pour le produit fini https://www.mobilesuica.work

La gestion des erreurs

La gestion des erreurs est un seuil élevé pour les amateurs comme l'auteur. C'est difficile car il est fait en prévision des exceptions qui peuvent survenir et du fonctionnement erroné de l'utilisateur (bien qu'il soit ajouté dans les résultats des tests, bien sûr).

Les deux traitements d'erreurs suivants sont considérés cette fois.

En regardant les liens ci-dessous et d'autres pages, j'ai pensé qu'il serait correct d'attraper l'exception avec try-except et de l'augmenter avec augmenter. La plupart des choses que vous récupérez sur GitHub sont comme ça. * Comment implémenter la notification d'erreur dans le programme Python

Juger si c'est PDF

J'en ai trouvé un pratique appelé ** PyPDF2 **.

test.py


import PyPDF2
with open('a.pdf','rb') as f:
    pageNum = PyPDF2.PdfFileReader(f).getNumPages()
    print(f"Le nombre de pages{pageNum}est")

Résultat d'exécution

(app-root) bash-4.2# python3 test.py
Le nombre de pages est de 2

Si vous transmettez un fichier non PDF, il ressemblera à ceci

test.py


fileList = ['a.pdf','test.py']
for fileName in fileList:
    with open(fileName,'rb') as f:
        pageNum = PyPDF2.PdfFileReader(f).getNumPages()
        print(f"{fileName}Le nombre de pages est{pageNum}est")

Résultat d'exécution

(app-root) bash-4.2# python3 test.py
a.Le nombre de pages en pdf est de 2
Traceback (most recent call last):
  File "test.py", line 9, in <module>
    pageNum = PyPDF2.PdfFileReader(f).getNumPages()
  File "/opt/app-root/lib/python3.6/site-packages/PyPDF2/pdf.py", line 1084, in __init__
    self.read(stream)
  File "/opt/app-root/lib/python3.6/site-packages/PyPDF2/pdf.py", line 1696, in read
    raise utils.PdfReadError("EOF marker not found")
PyPDF2.utils.PdfReadError: EOF marker not found

** PyPDF2.utils.PdfReadError: marqueur EOF introuvable ** semble être une exception que PyPDF2 lance lorsqu'il ne s'agit pas d'un fichier PDF. Le message semble changer en fonction du fichier passé, et il y avait également ** Impossible de lire le fichier PDF malformé **. Dans tous les cas, si vous ne gérez pas bien cette exception, le programme s'arrêtera ici.

Gestion des exceptions

Pour le moment, ce serait bien de pouvoir récupérer ** PyPDF2.utils.PdfReadError **.

test.py


try:
    fileList = ['a.pdf','test.py']
    for fileName in fileList:
        with open(fileName,'rb') as f:
            pageNum = PyPDF2.PdfFileReader(f).getNumPages()
            print(f"{fileName}Le nombre de pages est{pageNum}est")
except PyPDF2.utils.PdfReadError as e:
    print(f"ERROR: {e}Le PDF est incorrect")

Résultat d'exécution

(app-root) bash-4.2# python3 test.py
a.Le nombre de pages en pdf est de 2
ERROR:Marqueur EOF introuvable Le PDF est incorrect

Désormais, même si une exception se produit, le traitement peut être poursuivi. En fin de compte, vous pouvez informer l'utilisateur qui a téléchargé le fichier non PDF.

Cependant, il y a un inconvénient en soi. Puisqu'il n'y a pas de traceback, vous ne saurez pas plus tard où le programme s'est arrêté dans le code source. La solution est simple, il suffit d'utiliser un module appelé ** traceback **.

test.py


import traceback
#...réduction
except PyPDF2.utils.PdfReadError as e:
    print(f"ERROR: {e}Le PDF est incorrect")
    traceback.print_exc() 

Résultat d'exécution

(app-root) bash-4.2# python3 test.py
a.Le nombre de pages en pdf est de 2
ERROR:Marqueur EOF introuvable Le PDF est incorrect
Traceback (most recent call last):
  File "test.py", line 10, in <module>
    pageNum = PyPDF2.PdfFileReader(f).getNumPages()
  File "/opt/app-root/lib/python3.6/site-packages/PyPDF2/pdf.py", line 1084, in __init__
    self.read(stream)
  File "/opt/app-root/lib/python3.6/site-packages/PyPDF2/pdf.py", line 1696, in read
    raise utils.PdfReadError("EOF marker not found")
PyPDF2.utils.PdfReadError: EOF marker not found

Vous pouvez voir que la traceback est sortie contrairement au précédent.

En regardant le code source des autres, il dit ** sauf Exception comme e: **, donc je ramasse toutes les exceptions. Cela semble être appelé la classe de base. Après avoir lu diverses choses, si vous souhaitez modifier le traitement en fonction de l'exception que vous avez sélectionnée, spécifiez quelle exception comme ** PyPDF2.utils.PdfReadError **, sinon si le traitement est le même ** sauf Exception comme e: * * Mais ça a l'air bien. Par exemple, est-ce que c'est comme ça?

test.py


try:
    fileList = ['test.py']
    for fileName in fileList:
        with open(fileName,'rb') as f:
            pageNum = PyPDF2.PdfFileReader(f).getNumPages()
            print(f"{fileName}Le nombre de pages est{pageNum}est")
            df = tabula.read_pdf(fileName,pages='all',pandas_options={'dtype':'object'})
except PyPDF2.utils.PdfReadError as e:
    print(f"ERROR: {e}Le PDF est incorrect")
except Exception as e:
    print(f"ERROR: {e}Quelque chose ne va pas")

À propos, si vous écrivez la classe de base en premier, elle entrera la route de traitement là-bas, alors essayez d'écrire la classe de base en dernier.

Gestion des erreurs avec tabula-py

Il n'y a pas d'exceptions à donner un PDF non tabulaire, donc tout ce que vous avez à faire est de vous assurer qu'il ne s'agit pas d'un PDF Suica mobile. Tout d'abord, lisez l'en-tête DataFrame. J'ai préparé un fichier vierge (blank.pdf) en tant que mauvais PDF.

test.py


fileList = ['a.pdf','blank.pdf']
for fileName in fileList:
    df = tabula.read_pdf(fileName,pages='all',pandas_options={'dtype':'object'})
    h = df[0].columns.values.tolist()
    print(f"L'en-tête est{h}est")

Résultat d'exécution

(app-root) bash-4.2# python3 test.py
L'en-tête est['Mois', 'journée', 'Type', 'Station utilisée', 'Type.1', 'Station utilisée.1', 'Équilibre', 'différence']est
Traceback (most recent call last):
  File "test.py", line 11, in <module>
    h = df[0].columns.values.tolist()
IndexError: list index out of range

Apparemment, cela donne une erreur d'index, c'est donc une exception. Pour gérer les erreurs supplémentaires, il est possible que l'en-tête DataFrame ait été supprimé, mais un PDF tabulaire différent du PDF Mobile Suica a été téléchargé. Si vous vérifiez le contenu de l'en-tête, il apparaîtra, mais il semble créer un bogue différent, alors arrêtez la gestion des erreurs jusqu'à ce point. Le programme qui reçoit finalement la liste des fichiers téléchargés par l'utilisateur en tant que fileList et la traite est comme ça.

test.py


import tabula
import PyPDF2
import traceback
import pandas as pd

try:
    fileList = ['a.pdf','blank.pdf']
    dfList = []
    for fileName in fileList:
        with open(fileName,'rb') as f:
            pageNum = PyPDF2.PdfFileReader(f).getNumPages()
            df = tabula.read_pdf(fileName,pages='all',pandas_options={'dtype':'object'})
            if df[0].columns.values.tolist():
                for i in range(len(df)):
                    dfList.append(df[i])
                print(f"{fileName}Peut être traité correctement")
    d = pd.concat(dfList,ignore_index=True)
    
except PyPDF2.utils.PdfReadError as e:
    print(f"ERROR: {e} {fileName}Ne semble pas être en PDF")
    traceback.print_exc() 
except IndexError as e:
    print(f"ERROR: {e} {fileName}Est un PDF, mais il ne semble pas être un PDF mobile Suica")
    traceback.print_exc() 
except Exception as e:
    print(f"ERROR: {e} {fileName}Quelque chose ne va pas")
    traceback.print_exc() 

Résultat d'exécution

(app-root) bash-4.2# python3 test.py
a.pdf a été traité correctement
ERROR: list index out of range blank.pdf est un PDF, mais il semble que ce ne soit pas un PDF mobile Suica
Traceback (most recent call last):
  File "test.py", line 13, in <module>
    if df[0].columns.values.tolist():
IndexError: list index out of range

Gestion des exceptions personnalisée

Comme le traitement jusqu'à ce point sera appelé en tant que fonction, le message d'erreur n'apparaîtra que dans le journal du serveur et ne sera pas visible par l'utilisateur. Ce message d'erreur doit être renvoyé à l'appelant pour être visible par l'utilisateur. Si vous le renvoyez tel quel avec ** rise **, seul le message d'erreur d'origine sera envoyé. Quand il est transformé en fonction, il ressemble à ceci

test.py


def test():
    try:
        fileList = ['copy.sh']
        dfList = []
        for fileName in fileList:
            with open(fileName,'rb') as f:
                pageNum = PyPDF2.PdfFileReader(f).getNumPages()
                df = tabula.read_pdf(fileName,pages='all',pandas_options={'dtype':'object'})
                if df[0].columns.values.tolist():
                    for i in range(len(df)):
                        dfList.append(df[i])
                    print(f"{fileName}Peut être traité correctement")
        d = pd.concat(dfList,ignore_index=True)
        print(d)
        
    except PyPDF2.utils.PdfReadError as e:
        print(f"ERROR: {e} {fileName}Ne semble pas être en test PDF()dans")
        raise
    except IndexError as e:
        print(f"ERROR: {e} {fileName}Est un PDF, mais il ne semble pas être un PDF mobile Suica")
    except Exception as e:
        print(f"ERROR: {e} {fileName}Quelque chose ne va pas")

try:
    test()
except Exception as e:
    print(f"{e}Votre interlocuteur")

Résultat d'exécution

(app-root) bash-4.2# python3 test.py
ERROR: Could not read malformed PDF file copy.sh ne semble pas être en test PDF()dans
Impossible de lire l'appelant du fichier PDF malformé

Je ne sais pas quel fichier était mauvais. La seule façon de résoudre ce problème était de faire une exception, ce qui était un peu bosselé, mais j'étais soulagé que cela se soit avéré assez facile. Il y a une explication facile à comprendre sur ce site. Ajoutez simplement deux lignes! !! * Exemple de code (3 types) pour créer et utiliser des exceptions en Python

Voici donc celui avec votre propre gestion des exceptions

test.py


import tabula
import PyPDF2
import traceback
import pandas as pd

class ConvertError(Exception):
    pass

def test():
    try:
        fileList = ['copy.sh']
        dfList = []
        for fileName in fileList:
            with open(fileName,'rb') as f:
                pageNum = PyPDF2.PdfFileReader(f).getNumPages()
                df = tabula.read_pdf(fileName,pages='all',pandas_options={'dtype':'object'})
                if df[0].columns.values.tolist():
                    for i in range(len(df)):
                        dfList.append(df[i])
                    print(f"{fileName}Peut être traité correctement")
        d = pd.concat(dfList,ignore_index=True)
        print(d)
        
    except PyPDF2.utils.PdfReadError as e:
        traceback.print_exc() 
        errorText =  f"ERROR: {e} {fileName}Ne semble pas être en PDF=> test()dans"
        print(errorText)
        raise ConvertError(errorText)
    except IndexError as e:
        traceback.print_exc()
        errorText = f"ERROR: {e} {fileName}Est un PDF, mais il ne semble pas être un PDF mobile Suica"
        print(errorText)
        raise ConvertError(errorText)
    except Exception as e:
        traceback.print_exc()  
        errorText = f"ERROR: {e} {fileName}Quelque chose ne va pas"
        print(errorText)
        raise ConvertError(errorText)

try:
    test()
except Exception as e:
    print(f"{e}Votre interlocuteur")

Résultat d'exécution

(app-root) bash-4.2# python3 test.py
Traceback (most recent call last):
  File "test.py", line 15, in test
    pageNum = PyPDF2.PdfFileReader(f).getNumPages()
  File "/opt/app-root/lib/python3.6/site-packages/PyPDF2/pdf.py", line 1084, in __init__
    self.read(stream)
  File "/opt/app-root/lib/python3.6/site-packages/PyPDF2/pdf.py", line 1697, in read
    line = self.readNextEndLine(stream)
  File "/opt/app-root/lib/python3.6/site-packages/PyPDF2/pdf.py", line 1937, in readNextEndLine
    raise utils.PdfReadError("Could not read malformed PDF file")
PyPDF2.utils.PdfReadError: Could not read malformed PDF file
ERROR: Could not read malformed PDF file copy.sh ne semble pas être PDF=> test()dans
ERROR: Could not read malformed PDF file copy.sh ne semble pas être PDF=> test()Dans l'appelant

Recommended Posts

Examinez s'il s'agit d'un PDF et du traitement des exceptions Jusqu'à ce que vous créiez votre propre traitement des exceptions
Créez votre propre exception
Introduction à l'utilisation de Pytorch Lightning ~ Jusqu'à ce que vous formatez votre propre modèle et le produisez sur tensorboard ~
Jusqu'à ce que vous hébergiez vous-même votre propre interprète
Jusqu'à ce que vous obteniez un instantané du service Amazon Elasticsearch et que vous le restauriez