Extraire des images et des tableaux de pdf avec python pour réduire la charge de reporting

Contexte

Lors de la rédaction d'un rapport, il devenait gênant de découper et d'enregistrer des images (schémas électriques, etc.) à partir du pdf envoyé au format pdf, et de simplement copier le tableau. Les applications et le code utiles qui les font ne sont pas sortis en un coup d'œil. Alors faisons-le. L'extraction de table n'a pas fonctionné, mais j'ai pu obtenir les valeurs, donc la charge a été réduite (; ^ _ ^ A)

Je le mets aussi sur git donc si ça va https://github.com/kzrn3318/create_img_excel_from_pdf

environnement

Installation des bibliothèques requises


pip install pypdf2
pip install pillow
pip install PyMuPDF
pip install fitz
pip install pandas
pip install camelot-py[cv]

Si vous n'avez pas ghostscript au moment de l'exécution, vous pouvez obtenir une erreur. Dans ce cas, veuillez installer ghostscript. Comme il s'agit de windows10 au moment de la création du code, il peut ne pas fonctionner avec d'autres systèmes d'exploitation en raison de la chaîne de caractères du chemin, dans ce cas, veuillez réécrire afin que le chemin du code puisse être appliqué. Nous n'avons pas confirmé l'opération avec d'autres os.

Corps du code

Ci-dessous le code

main.py


import PyPDF2
from PIL import Image
import sys,os
import glob
import fitz
import camelot
import pandas as pd

def create_dir(img_dir , pdf_dir , excel_dir):
    img_dir_glob = glob.glob(str(img_dir))
    pdf_dir_glob = glob.glob(str(pdf_dir))
    excel_dir_glob = glob.glob(str(excel_dir))
    
    if len(pdf_dir_glob) > 0:
        pass
    else:
       os.mkdir(str(pdf_dir))
       
    if len(img_dir_glob) > 0:
        pass
    else:
        os.mkdir(str(img_dir))
    
    if len(excel_dir_glob) > 0:
        pass
    else:
        os.mkdir(str(excel_dir))
        

def create_page_pdf(pdf,page_count,pdf_dir):
    pdf_writer = PyPDF2.PdfFileWriter()
    pdf_writer.addPage(pdf.getPage(page_count))
    
    with open(".\\"+str(pdf_dir)+"\pdf{}.pdf".format(page_count),"wb") as f:
        pdf_writer.write(f)
    

def create_png(pdf_path,page_count,img_dir):
    pdf  = fitz.open(pdf_path)
    for num in range(len(pdf)):
        num_count = 0
        for image in pdf.getPageImageList(num):
            num_count += 1
            xref = image[0]
            pix = fitz.Pixmap(pdf,xref)
            
            if pix.n < 5:
                pix.writePNG(".\\"+str(img_dir)+"\img{}_{}.png ".format(page_count,num_count))
            else:
                pix = fitz.Pixmap(fitz.csRGB,xref)
                pix.writePNG(".\\"+str(img_dir)+"\img{}_{}.png ".format(page_count,num_count))
            
            pix = None
    
    pdf.close()
    
    
def create_excel(pdf_path,excel_dir,data_count):
    
    datas = camelot.read_pdf(pdf_path,split_text=True)
    data_count = data_count
    for data in datas:
        data_count += 1
        df =  data.df
        with pd.ExcelWriter(".\\"+str(excel_dir)+"\\from_pdf_{}.xlsx".format(data_count)) as file:
            df.to_excel(file,sheet_name="sheet1",index=False,header=False)
    return data_count


if __name__ == "__main__":
    args = sys.argv
    print([i for i in args])
    if len(args) >= 5:
        print("Reçu un argument.")
        pdf_file = args[1]
        pdf_dir = args[2]
        img_dir = args[3]
        excel_dir = args[4]
    else:
        try:
            pdf_file = args[1]
            print("Étant donné que l'argument n'a pas été spécifié, la valeur par défaut est utilisée.")
        except:
            raise ValueError("Au moins un fichier pdf doit être l'argument. Lorsque vous spécifiez le répertoire de sortie, spécifiez quatre arguments.")
        pdf_dir ="pdf_list"
        img_dir="img_list"
        excel_dir="excel_data"
    
    pdf = PyPDF2.PdfFileReader(pdf_file)
    
    print("Répertoire d'images:"+str(img_dir))
    print("Répertoire pdf de chaque page:"+str(pdf_dir))
    print("Répertoire de données Excel:"+str(excel_dir))
    
    create_dir(img_dir,pdf_dir,excel_dir)
    
    page_count = 0
    for page in pdf.pages:
        create_page_pdf(pdf,page_count,pdf_dir)
        page_count += 1
        
    path_list = glob.glob(".\\"+pdf_dir+"\*.pdf")
    page_count = 0
    data_count = 0
    for path in path_list:
        page_count += 1
        create_png(path,page_count,img_dir)
        data_count = create_excel(path,excel_dir,data_count)
        
    print("Sortie de traitement\n")

La méthode d'exécution est la suivante, veuillez exécuter dans le même répertoire que le pdf cible. Au moment de l'exécution, un répertoire pour sauvegarder le pdf paginé, un répertoire pour sauvegarder l'image extraite du pdf, et un répertoire pour extraire le tableau du pdf et l'enregistrer sont créés. Vous pouvez les spécifier avec des arguments de ligne de commande.

python main.py (Cible.pdf) (répertoire paginé pdf) (répertoire d'images d'extraction pdf) (répertoire d'extraction de table pdf)

Exemple


python main.py train1.pdf pdf_dir img_dir excel_dir

Dans l'exemple ci-dessus, le pdf est enregistré pour chaque division de page directement sous pdf_dir. Enregistrez l'image extraite dans img_dir. Enregistrez la table extraite dans excel_dir converti en excel.

Explication partielle du code

import PyPDF2
from PIL import Image
import sys,os
import glob
import fitz
import camelot
import pandas as pd

Comme vous pouvez le voir, les gens qui écrivent habituellement python le voient souvent. Importez chaque package.

def create_dir(img_dir , pdf_dir , excel_dir):
    img_dir_glob = glob.glob(str(img_dir))
    pdf_dir_glob = glob.glob(str(pdf_dir))
    excel_dir_glob = glob.glob(str(excel_dir))

    if len(pdf_dir_glob) > 0:
        pass
    else:
       os.mkdir(str(pdf_dir))

    if len(img_dir_glob) > 0:
        pass
    else:
        os.mkdir(str(img_dir))

    if len(excel_dir_glob) > 0:
        pass
    else:
        os.mkdir(str(excel_dir))

Il s'agit d'une fonction de création de répertoire qui détermine si l'argument reçu existe déjà et le crée s'il n'existe pas.

def create_page_pdf(pdf,page_count,pdf_dir):
    pdf_writer = PyPDF2.PdfFileWriter()
    pdf_writer.addPage(pdf.getPage(page_count))

    with open(".\\"+str(pdf_dir)+"\pdf{}.pdf".format(page_count),"wb") as f:
        pdf_writer.write(f)

C'est une fonction qui divise le pdf original en pages et enregistre chacune. Créez un pdf (numéro de page) .pdf directement sous pdf_dir.

def create_png(pdf_path,page_count,img_dir):
    pdf  = fitz.open(pdf_path)
    for num in range(len(pdf)):
        num_count = 0
        for image in pdf.getPageImageList(num):
            num_count += 1
            xref = image[0]
            pix = fitz.Pixmap(pdf,xref)

            if pix.n < 5:
                pix.writePNG(".\\"+str(img_dir)+"\img{}_{}.png ".format(page_count,num_count))
            else:
                pix = fitz.Pixmap(fitz.csRGB,xref)
                pix.writePNG(".\\"+str(img_dir)+"\img{}_{}.png ".format(page_count,num_count))

            pix = None

    pdf.close()

Enregistrez l'image extraite directement sous img_dir au format .png. Le nom du fichier sera img (numéro de page) _ (numéro d'image sur la page) .png.

def create_excel(pdf_path,excel_dir,data_count):

    datas = camelot.read_pdf(pdf_path,split_text=True)
    data_count = data_count
    for data in datas:
        data_count += 1
        df =  data.df
        with pd.ExcelWriter(".\\"+str(excel_dir)+"\\from_pdf_{}.xlsx".format(data_count)) as file:
            df.to_excel(file,sheet_name="sheet1",index=False,header=False)
    return data_count

Enregistrez le fichier Excel converti directement sous excel_dir.

def create_excel(pdf_path,excel_dir,data_count):

    datas = camelot.read_pdf(pdf_path,split_text=True)
    data_count = data_count
    for data in datas:
        data_count += 1
        df =  data.df
        with pd.ExcelWriter(".\\"+str(excel_dir)+"\\from_pdf_{}.xlsx".format(data_count)) as file:
            df.to_excel(file,sheet_name="sheet1",index=False,header=False)
    return data_count


if __name__ == "__main__":
    args = sys.argv
    print([i for i in args])
    if len(args) >= 5:
        print("Reçu un argument.")
        pdf_file = args[1]
        pdf_dir = args[2]
        img_dir = args[3]
        excel_dir = args[4]
    else:
        try:
            pdf_file = args[1]
            print("Étant donné que l'argument n'a pas été spécifié, la valeur par défaut est utilisée.")
        except:
            raise ValueError("Au moins un fichier pdf doit être l'argument. Lorsque vous spécifiez le répertoire de sortie, spécifiez quatre arguments.")
        pdf_dir ="pdf_list"
        img_dir="img_list"
        excel_dir="excel_data"

    pdf = PyPDF2.PdfFileReader(pdf_file)

    print("Répertoire d'images:"+str(img_dir))
    print("Répertoire pdf de chaque page:"+str(pdf_dir))
    print("Répertoire de données Excel:"+str(excel_dir))

    create_dir(img_dir,pdf_dir,excel_dir)

    page_count = 0
    for page in pdf.pages:
        create_page_pdf(pdf,page_count,pdf_dir)
        page_count += 1

    path_list = glob.glob(".\\"+pdf_dir+"\*.pdf")
    page_count = 0
    data_count = 0
    for path in path_list:
        page_count += 1
        create_png(path,page_count,img_dir)
        data_count = create_excel(path,excel_dir,data_count)

    print("Sortie de traitement\n")

C'est la partie exécution de main.py. Chaque nom de répertoire est obtenu à partir de l'argument de ligne de commande et exécuté.

Résumé

Jusqu'à présent, j'avais l'habitude de découper du pdf, mais je pense que c'est devenu beaucoup plus facile. pyPDF2 et camelot avaient très peu de rayures et étaient difficiles (-_-;) Il semble qu'il y ait encore des améliorations dans l'extraction de table, mais cela semble difficile à extraire car cela est dû à la structure et au style d'écriture du pdf. Ce code est créé en supposant que le pdf exporté est utilisé. Veuillez noter que nous n'avons pas testé si le livre d'instructions PDF numérisé par Adobe Scan, etc.

Recommended Posts

Extraire des images et des tableaux de pdf avec python pour réduire la charge de reporting
Extraire le texte du pdf [python] et lire les caractères à haute voix avec Open-Jtalk
De l'introduction de JUMAN ++ à l'analyse morphologique du japonais avec Python
Extraire des tables de base de données avec CSV [connexion ODBC de R et python]
[Python] Essayez de reconnaître les caractères des images avec OpenCV et pyocr
Je souhaite extraire une URL arbitraire de la chaîne de caractères de la source html avec python
Deep Learning from scratch La théorie et la mise en œuvre de l'apprentissage profond appris avec Python Chapitre 3
Les images créées avec matplotlib passent de dvi à pdf
Extraire le tableau des fichiers image avec OneDrive et Python
Le mur lors du passage du service Django de Python 2.7 à la série Python 3
Apprenez Nim avec Python (dès le début de l'année).
Visualisez la gamme d'insertions internes et externes avec python
Convertissez l'image au format .zip en PDF avec Python
J'ai essayé d'automatiser la mise à jour de l'article du blog Livedoor avec Python et sélénium.
Je voulais juste extraire les données de la date et de l'heure souhaitées avec Django
J'ai essayé de comparer la vitesse de traitement avec dplyr de R et pandas de Python
J'ai essayé de trouver l'entropie de l'image avec python
Extraire le modèle du fichier EML enregistré depuis Thunderbird avec python3.7
Probablement le moyen le plus simple de créer un pdf avec Python 3
Convertissez des images numérisées déformées en PDF avec Pillow et PyPDF
Essayez d'automatiser le fonctionnement des périphériques réseau avec Python
Je veux connaître la nature de Python et pip
Enregistrer des images sur le Web sur un lecteur avec Python (Colab)
Jouez avec le mécanisme de mot de passe de GitHub Webhook et Python
Récupérez la source de la page à charger indéfiniment avec python.
Extraire la valeur la plus proche d'une valeur à partir d'un élément de liste en Python
Essayez d'extraire les caractéristiques des données de capteur avec CNN
Comment gratter le cours d'une action individuelle du site Web Nikkei Shimbun avec Python
Renvoyez les données d'image avec Flask of Python et dessinez-les dans l'élément canvas de HTML
Comment connaître le nombre de GPU de python ~ Remarques sur l'utilisation du multitraitement avec pytorch ~
Introduction à la création d'IA avec Python! Partie 1 J'ai essayé de classer et de prédire le nombre à partir de l'image du numéro manuscrit
Faites fonctionner Jupyter avec l'API REST pour extraire et enregistrer le code Python
Extraire le fichier xz avec python
L'histoire de Python et l'histoire de NaN
Répétez avec While. Script pour tweeter ou rechercher depuis le terminal
[Introduction à Python] J'ai comparé les conventions de nommage de C # et Python.
Existence du point de vue de Python
Je veux sortir le début du mois prochain avec Python
Exportez le contenu de ~ .xlsx dans le dossier en HTML avec Python
Essayez d'extraire une chaîne de caractères d'une image avec Python3
Extraire du texte d'images avec Python
Publier une image de Python sur Tumblr
Traitez le fichier gzip UNLOADed avec Redshift avec Python de Lambda, gzipez-le à nouveau et téléchargez-le sur S3
Pour améliorer la réutilisabilité et la maintenabilité des flux de travail créés avec Luigi
Convertissez le résultat de python optparse en dict et utilisez-le
Essayez de calculer la position de l'émetteur à partir du modèle de propagation des ondes radio avec python [Wi-Fi, Beacon]
J'ai essayé d'améliorer l'efficacité du travail quotidien avec Python
Coexistence de Python2 et 3 avec CircleCI (1.0)
Utilisez Firefox avec Selenium depuis python et enregistrez la capture d'écran
J'ai essayé de collecter automatiquement des images de Kanna Hashimoto avec Python! !!
Le moyen le plus rapide d'obtenir régulièrement des images de caméra avec opencv de python
PhytoMine-I a essayé d'obtenir les informations génétiques de la plante avec Python
Résoudre avec Python [100 questions passées sélectionnées que les débutants et les intermédiaires devraient résoudre] (005 --- 009 Toutes les recherches: Toutes les énumérations pour réduire le nombre de rues en concevant)
[Python] Trois méthodes pour comparer la liste des tableaux à une dimension et la liste des tableaux à deux dimensions et extraire uniquement les valeurs correspondantes [json]