Traitement de PDF (séparation, renommage, deplacement)

Bonjour à tous,

Je ne sais pas si vous accepterez de m’aider (parce qu’il y a du taff :D) mais je tente tout de même le coup on sait jamais.

Je suis total débutant sur Python, jusque là j’ai développé tout mes projets avec AutoIt mais pour celui ci je tourne en rond alors après recherche je pense qu’il serait réalisable sur Python.

concrètement, j’ai besoin de développer une app pour effectuer le traitement de pdf selon le process suivant :

  • les fichiers pdf a traiter son des numérisation de plusieurs documents de plusieurs page en une seule numérisation dont chaque première page contient 2 informations en bas de page (1 pour le renommage et 1 mot clé indiquant le début d’un nouveau document)
  • premier traitement a réaliser, séparer chaque pdf a chaque fin d’un document en utilisant le mot clé.
  • second traitement, renommer les pdf généré en fonction de l’information de renommage qui n’est pas toujours la même (exemple “recu_2401102501”, “naiss_01011005” ou encore procctx_24051206_05… j’en ai une cinquantaine comme ça et les partie en chiffre n’est pas toujours sur le même nombre de caractères
  • troisième traitement déplacer les fichier pdf dans des dossiers réseaux en fonction de la première partie de leur nom (la partie en lettres)
  • dernier traitement, supprimer les fichiers d’origine.

Information supplémentaire : les fichiers arrivent au fil de l’eau il est donc possible qu’entre le lancement et la fin des traitements, de nouveaux fichiers soient déposé. Il ne faut donc pas les prendre en compte dans la dernière étape de suppression.

Idéalement il faudrait alimenter un fichier log a chaque étape de traitement.

Comme je l’ai dit je suis total débutant et je suis donc très vite coincé. pour le moment je n’arrive qu’a séparer en plusieurs fichiers sur détection du mot clé et uniquement pour des fichiers sur lesquels il y a eu de l’OCR de faite par le copieur servant aux numérisation. Problème certain fichier font pas loin de 100 pages donc l’OCRisation (si je puis dire) est très longue et le poids du fichier on en parle même pas… De plus je n’arrive a le faire qu’en ciblant un fichier en particulier.

Bref vous l’aurez compris a ce stade c’est même pas de l’entraide c’est limite de l’assistanat j’en suis conscient.

pour info j’ai utilisé PyPDF2

Je vous remercie par avance pour vos retour.
Ptiseb

Tu as peut-être des librairies externes capables de faire certaines choses pour la manipulation du PDF lui-même comme pdftk ?

Pour le reste, le renommage et le déplacement, pour moi c’est pas un souci avec les modules os et shutil.

Enfin, pour la gestion des documents à traiter, tu pourrais t’appuyer sur “rq”, une librairie qui permet justement de dédier un travail précis dans une queue qui gère ça.
Ainsi, chaque fichier reçu est positionné dans la queue et traité au fur et à mesure (tu peux avoir plusieurs “worker” pour accélérer le processus et traiter plusieurs fichiers en parallèle bien entendu).

Bonjour Mindiell et merci pour ce premier retour.

J’ai regardé pdftk mais a priori il n’apporte rien de plus que pypdf2.
merci pour os et shutil je vais regarder comment m’en servir.

rq semble être en effet une bonne solution pour pouvoir mettre en file d’attente et éviter de traiter plusieurs fois le même fichier. Ce qui me gène c’est qu’il nécessite visiblement un serveur redis et donc un environnement linux or mon serveur exécutant déjà différentes taches d’automatisation est sous Windows server 2019.

Je me demande si je ne parviendrais pas a mes fins (sans la partie multi workers) avec la fonction listdir d’os?

Bon j’ai un peu avancé (je dis bien un peu…)
concrètement maintenant j’arrive a traiter l’ensemble des fichiers d’un dossier de dépôt a partir du moment où ils sont déjà passé par de l’OCR.
J’arrive a les séparer en plusieurs PDF a détection d’un mot clé.

Par contre je perd les pages qui ne comportent pas ce mot clé.
Il me crée un pdf par page contenant mon mot clé au lieu de créer un pdf de plusieurs pages jusqu’à ce qu’il rencontre a nouveau le mot clé et donc recommence un nouveau pdf a partir de là.

pourriez vous jeter un coup d’œil a mon code et me dire ce que j’aurais loupé svp?

from os import listdir
import re, PyPDF2, datetime, logging

#déinition fichier de log
if __name__ == "__main__":
    logging.basicConfig(level=logging.DEBUG, filename="logfile.log", filemode="a+",
                        format="%(asctime)-15s %(levelname)-8s %(message)s")
#début des traces dans le log
now = datetime.datetime.now()
logging.info("execution du : ")
logging.info(now.strftime("%d-%m-%Y %H:%M:%S"))

#definition des chemins
fichiers="\\\\nom-serveur\\chemin dossier de depot des fichier a traiter\\"
dest="\\\\nom-serveur\\chemin dossier temporaire des fichiers séparés\\"

#recupération de la liste des fichiers a traiter
allFiles=listdir(fichiers)
allFiles = [i for i in allFiles if '.pdf' in i]
logging.info('{} files'.format(len(allFiles)))

for f in allFiles:
    pdf_file = PyPDF2.PdfReader(open(fichiers + f, "rb"))

    # définition du regex de séparation des pdfs
    pattern = re.compile("mot clé de séparation")

    # boucle sur chaques pages du pdf
    for i in range(len(pdf_file.pages)):
        page = pdf_file.pages[i]
        text = page.extract_text()

        # Check si le regex est present dans la page courante
        if pattern.search(text):
            logging.info('mot clé de séparation trouvé page '"{}".format(i) + ' du fichier '"{}".format(f))
            output_pdf = PyPDF2.PdfWriter()
            output_pdf.add_page(page)
            with open(dest + "_{}.pdf".format(i), "wb") as output_file:
                output_pdf.write(output_file)
            logging.info('fichier '"_{}.pdf".format(i) + ' créé dans : ' + dest)

        else: logging.info('mot clé de séparation non trouvé dans la page '"{}".format (i) +' du fichier '"{}".format(f))

C’est assez logique, car tu n’écris un nouveau fichier que lorsque tu rencontres le mot clef.

Tu devrais suivre ces étapes :

  1. ouvrir un fichier pour écrire dedans
  2. pour chaque page du fichier lu
    2.1. si le fichier lu contient le mot
    2.1.1. sauver le fichier en cours d’écriture
    2.1.2. ouvrir un fichier pour écrire dedans
    2.2. ajouter la page dans le fichier en cours d’écriture
  3. sauver le fichier en cours d’écriture

Ainsi, tu devrais obtenir n+1 fichiers en partant d’un fichier ayant n pages avec le mot clef

Mon bout de code est issue de différents bout de code trouvé sur le net, j’avoue ne pas encore avoir compris toutes ses subtilités…
Aurait tu un bout de code en exemple car même si je pense avoir compris ta description des étapes a suivre, je ne parviens pas a l’appliquer.

Ah, si tu ne comprends pas les bouts de code récupérés sur les internets et que tu veux que je te file juste un bout de code, ça ne te fera pas progresser.

Je préconise plutôt un travail d’apprentissage : tu essayes d’appliquer ce que j’ai dit, en commentant le code, et si ça ne fonctionne pas comme prévu tu poses des questions :wink:

“Donne un poisson à une personne, elle mangera un jour. Apprends-lui à pêcher, elle mangera toute sa vie.”

2 « J'aime »

Je te rassure je ne demande pas des bouts de code tout fait sans chercher a comprendre. Mais je pense qu’un exemple concret accompagné d’explication sont bien plus formateur que de simples indications. Une nouvelle fois je débute en python et je préfère apprendre sur du concret que de suivre bêtement des tuto qui n’ont aucun sens pour moi. Malheureusement les besoins de mon cas concret nécessite je pense des notions pas évidentes pour un débutant d’où mon appel a l’aide…

J’ai essayé de suivre tes indications et il y a du mieux dans le sens où je ne perd plus de page en revanche chaque page s’enregistre dans un nouveau pdf.
Je n’arrive pas a comprendre comment ajouter les pages a celle de départ contenant mon mot clé de séparation.

D’ailleurs plus j’y repense et plus je me demande si ca ne devrait pas plutôt être :

  1. ouvrir un fichier pour écrire dedans
  2. pour chaque page
    2.1. si mot clé détecté
    2.1.1 ajouter la page au fichier en cours
    2.1.2 enregistrer le fichier en cours
    2.2 sinon ouvrir le précédant fichier
    2.2.1 ajouter la page
    2.2.2 enregistrer le fichier en cours

Bon j’ai pu avancer un peu.
J’arrive maintenant a créer autant de fichier pdf qu’il y a de page avec le mot clé de séparation.
Dans chaque fichier j’arrive a ajouter les pages sans mot clé et dans le bon ordre.
Par contre le premier fichier pdf généré de chaque fichier traité est illisible ou endommagé et je ne comprend pas trop pourquoi.

Voici où j’en suis :

from os import listdir
from PyPDF2 import PdfMerger, PdfReader
import re, PyPDF2, datetime, logging

#déinition fichier de log
if __name__ == "__main__":
    logging.basicConfig(level=logging.DEBUG, filename="logfile.log", filemode="a+",
                        format="%(asctime)-15s %(levelname)-8s %(message)s")
#début des traces dans le log
now = datetime.datetime.now()
logging.info("execution du : ")
logging.info(now.strftime("%d-%m-%Y %H:%M:%S"))

#definition des chemins
fichiers="chemin vers les fichiers a traiter"
dest="chemin temporaire de destination"

#recupération de la liste des fichiers a traiter
allFiles=listdir(fichiers)
allFiles = [i for i in allFiles if '.pdf' in i]
logging.info('{} files'.format(len(allFiles)))



for f in allFiles:
    pdf_file = PyPDF2.PdfReader(open(fichiers + f, "rb"))

    # définition du regex de séparation des pdfs
    pattern = re.compile("mot clé de separation")

    j = 0
    # ouvre nouveau pdf
    output_pdf = PyPDF2.PdfWriter()

    # boucle sur chaques pages du pdf
    for i in range(len(pdf_file.pages)):
        page = pdf_file.pages[i]
        text = page.extract_text()

        # Check si le regex n'est pas present dans la page courante
        if not pattern.search(text):
            output_pdf.add_page(page)
        else:
            j = j + 1
            with open(dest + "_{}.pdf".format(j), "wb") as output_file:
                output_pdf.write(output_file)
            output_pdf = PyPDF2.PdfWriter()
            output_pdf.add_page(page)

1 « J'aime »

Ah super tout ça ! Comme quoi :o)
Pour les étapes, rouvrir un fichier précédent me semble une mauvaise idée, mais tu ne le fais pas dans ton code final, donc ça me plaît bien.

Le code
Concernant ton code il y a plusieurs points que je note après une rapide lecture :

from PyPDF2 import PdfMerger, PdfReader
import re, PyPDF2, datetime, logging

Ici, tu importes PyPDF2 alors que tu importes déjà certains objets. Tu peux importer PdfWriter sur la première ligne et ne pas importer PyPDF2 en dessous. Le reste de ton code pourra donc utiliser directement les classes importées :

pdf_file = PyPDF2.PdfReader(open(fichiers + f, "rb"))
devient donc :
pdf_file = PdfReader(open(fichiers + f, "rb"))

Ensuite cette boucle est une preuve que tu viens d’un autre langage de programmation a priori :

    # boucle sur chaques pages du pdf
    for i in range(len(pdf_file.pages)):
        page = pdf_file.pages[i]
        text = page.extract_text()

En python, il est plus pratique de faire ça :

    # boucle sur chaques pages du pdf
    for page in pdf_file.pages:
        text = page.extract_text()

ça permet de naviguer sur chaque objet de la liste.

Enfin, le dernier bout de code :

        # Check si le regex n'est pas present dans la page courante
        if not pattern.search(text):
            output_pdf.add_page(page)
        else:
            j = j + 1
            with open(dest + "_{}.pdf".format(j), "wb") as output_file:
                output_pdf.write(output_file)
            output_pdf = PyPDF2.PdfWriter()
            output_pdf.add_page(page)

serait peut-être plus lisible et sans multiplier les mêmes codes ainsi :

        # Check si le regex est pas présent dans la page courante
        if pattern.search(text):
            j = j + 1
            with open(dest + f"_{j}.pdf", "wb") as output_file:
                output_pdf.write(output_file)
            output_pdf = PyPDF2.PdfWriter()

        output_pdf.add_page(page)

J’ai également profité du cas pour utiliser une f-string (chaine de caractère qui commence par la lettre “f” et qui permet de formater la chaine). C’est assez évident à comprendre dans ton cas :wink:

Voilà pour un premier retour rapide !

Le souci
Concernant ton souci, la seule chose que je vois avec ton code actuel (et les améliorations que je propose) ne prend pas en compte les cas où il y a un mot-clef dans la première page. Dans ce cas, tu sauves un fichier vide.

Peut-être utiliser un simple booléen pour vérifier si tu as déjà ajouté des pages ?

Ca ne sert donc que pour un fichier sur lequel le mot-clef est sur la première page. Pour les autres cas, ça devrait aller.

Autre souci
Je vois qu’en fin de fichier, tu ne sauves pas le résultat des dernières pages. Il faudrait donc sauver le output_pdf après ta boucle des pages…

Bon courage !

Je te remercie pour ce retour très constructif.
Je vais l’analyser avec soin afin de bien le comprendre avant de l’appliquer :wink:

En effet, je ne suis pas développeur de formation mais pour les divers besoins d’automatisation j’ai été amené a m’autoformer sur un autre outil “AutoIt” qui est un mix de plusieurs langages et finalement très intuitif. Il existe dessus des librairies pour traiter les pdf mais je n’ai rien trouvé de satisfaisant pour la seconde partie de mon projet que je n’ai même pas encore abordé a savoir l’OCR pour les fichiers pdf n’ayant pas subit de reconnaissance d’écriture (il faudra que je me penche sur des choses comme tesseract j’imagine).

pour en revenir a mon précédant post, je me rend compte d’une erreur d’analyse de ma part.
En faite mon premier fichier pdf n’est pas vide. Enfin, j’ai bien un premier pdf vide qui est créé mais il ne correspond pas aux premières pages de mon pdf d’origine car je les retrouve bien dans le second fichier généré. En revanche tu as raison mon dernier pdf a créer pour chaque fichier traité n’était pas enregistré.

je dois avoir un truc qui traine dans un coin, ça découpait un fichier PDF en pages uniques (via pdftk), puis, pour chaque page ça faisait l’OCR. Puis ça recompilait l’OCR final global. J’avais fait ça, je crois, pour le code source du bidule qui a emmené les astronautes sur la lune, le PDF trainait en ligne :o)