[Python] Suite - Convertir le texte PDF en CSV page par page

Après précédent, j'ai pensé que cette réparation était nécessaire, donc c'est une simple continuation.

Le début de l'affaire

Il est normal de sortir la page PDF au format CSV, mais j'ai dit que c'était une tonne de données de démonstration. Plus précisément, le sous-titre est venu au milieu. C'est sobre et douloureux.

Quand je n'ai pas pu trouver un projet similaire, j'ai trouvé le site suivant. Analyse de la liste des entreprises noires du ministère de la Santé, du Travail et du Bien-être social avec Python (PDFMiner.six)

Je savais que j'avais un camarade et que je pouvais me débrouiller avec les coordonnées. Alors je vais l'essayer.

Vérification-Préparation-

Référence: Sélectionnez PDFMiner pour extraire les informations textuelles du PDF

Il semble que pdfminer puisse également obtenir les informations de coordonnées de la mise en page. Jusqu'à présent, seules les données de caractères étaient extraites avec TextConverter, Dans PDFPageAggregator, les coordonnées et les données de caractères semblent être extraites, alors utilisez ceci.

Pour le moment, vérifiez quels types de coordonnées sont disponibles. Je suis désolé de ne pas avoir pu préparer l'exemple de PDF ...

from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.converter import TextConverter, PDFPageAggregator
from pdfminer.layout import LAParams, LTContainer, LTTextBox, LTTextLine, LTChar
from pdfminer.pdfpage import PDFPage

def convert_pdf_to_txt(self,p_d_f):
    
    fp = open(p_d_f, 'rb')
    for page in PDFPage.get_pages(fp):
        
        rsrcmgr = PDFResourceManager()
        laparams = LAParams()
        laparams.detect_vertical = True
        device = PDFPageAggregator(rsrcmgr, laparams=laparams)
        interpreter = PDFPageInterpreter(rsrcmgr, device)
        
        #Obtenez des coordonnées et des données de caractères à partir de PDF
        interpreter.process_page(page)
        layout = device.get_result()
        
        #Affichage des coordonnées et des caractères
        for node in layout:
            if isinstance(node, LTTextBox) or isinstance(node, LTTextLine):
                print(node.get_text())   #lettre
                word =input(node.bbox)   #Coordonner
        word =input("---page end---")

Un gars inefficace qui vérifie à l'invite de commande.

Pour être honnête, je ne comprends pas vraiment le jugement comme LTTextBox, mais je l'ai mis comme une magie. Découvrons correctement.

résultat de l'inspection-

Ceci est un extrait du résultat de sortie. Le texte est factice.

---page end---
À propos de la machine à pop-corn

(68.28, 765.90036, 337.2, 779.9403599999999)
C'est une machine qui éclate et fait du pop-corn.

(67.8, 697.71564, 410.4000000000001, 718.47564)
Soyez prudent lorsque vous l'utilisez.

(67.8, 665.29564, 339.8400000000002, 686.05564)
L'utilisation est la suivante.

(67.8, 643.69564, 279.3600000000001, 653.65564000)
La description

(67.8, 730.11564, 87.96000000000001, 740.07564)

Taple est la coordonnée. L'ordre est (x0, y0, x1, y1). Pour plus de détails, rendez-vous sur le site de référence! Pour faire simple, si vous regardez y1, vous pouvez voir les coordonnées des caractères du bas. En d'autres termes, si y1 dans la page est dans l'ordre décroissant, les caractères sont disposés dans l'ordre du haut = forme de disposition correcte (dans ce cas).

Donc, en regardant ce résultat de sortie, y1 dans la dernière ligne est le deuxième plus grand, donc c'est un résultat non pertinent du point de vue de la simple disposition du haut. Il peut être trié en fonction de x0. Je ne sais rien. Il semble que les coordonnées sont bien prises, donc je vais faire quelque chose avec ce y1.

Solution proposée

① Faites un dictionnaire ② Trier le dictionnaire (ordre décroissant des touches) ③ Faites-en une chaîne de caractères ④ Nettoyez les sauts de ligne

Cela devrait fonctionner. Si vous êtes une personne sournoise, veuillez ne regarder que le produit fini.

① Faites un dictionnaire

d=[]
for node in layout:
    if isinstance(node, LTTextBox) or isinstance(node, LTTextLine):
        y1 = node.bbox[3]
        #S'il s'agit d'une table, les coordonnées de y1 sont dupliquées, donc une jointure de chaîne
        if y1 in d:
           d[y1] += "|" + node.get_text()
        else:
           d[y1] = node.get_text()

Créez un dictionnaire rapide des coordonnées et des caractères. Je prends également des mesures à table pour me détendre.

Mais pour être honnête, cette méthode pour l'ouvrir est un effort stérile car elle a des trous. La raison en est que les coordonnées ci-dessus semblent prendre des caractères ligne par ligne, mais le mécanisme consiste à définir une valeur semblable à un remplissage de marge et à prendre un bloc de caractères dans un proche avenir comme un "bloc". Il semble que ce soit (certainement).

Histoire solide, si vous ne définissez rien, la marge par défaut sera appliquée et plusieurs lignes seront reconnues comme un bloc pour les phrases avec un interligne serré et des tableaux fins. Donc, si vous obtenez plusieurs lignes de caractères avec les mêmes coordonnées, c'est déjà un repli de l'opération de table Ese.

Si tel est le cas, je parle de définir correctement le remplissage des marges, mais cette fois je ne demande pas beaucoup, donc je ne le définirai pas en particulier. Quand la table sort, essayons avec un sentiment de "je suis désolé!"

② Trier le dictionnaire (touche décroissante)

Référence: Résumé du tri Python (liste, type de dictionnaire, série, DataFrame)

d2 = sorted(d.items(), key=lambda x: -x[0])

Je l'ai fait! Ramuda Hatsuyoshi! Au fait, si vous faites cela, le dictionnaire sera une liste. Je m'en fiche tant que je peux trier.

③ Faites-en une chaîne de caractères

text = ""
for d0 in d2:
     text += d0[1]

C'est juste rond et rond.

④ Nettoyez les sauts de ligne

Référence: Diviser les chaînes séparées par des virgules avec Python, diviser, supprimer les blancs et la liste Je vous suis toujours redevable.

space = re.compile("[  ]+")
text = re.sub(space, "", text )
l_text = [a for a in text.splitlines() if a != '']
text = '\n'.join(l_text).replace('\n|', '|')

Il existe de nombreux espaces et sauts de ligne, c'est une solution au problème. Remplacez les espaces blancs et supprimez les sauts de ligne sous forme de liste. À propos, le saut de ligne avant le symbole qui a été utilisé comme marque lors du retour à la table est également supprimé.

Produit fini


from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.converter import TextConverter, PDFPageAggregator
from pdfminer.layout import LAParams, LTContainer, LTTextBox, LTTextLine, LTChar
from pdfminer.pdfpage import PDFPage

import csv,re,datetime
import pandas as pd

class converter(object):
    def convert_pdf_to_txt(self,p_d_f):
        print("system:pdf【" + p_d_f + "] Est lu")
        
        df = pd.DataFrame(columns=["Mettre à jour la date et l'heure","Phrase","numéro de page"])
        
        cnt = 1
        space = re.compile("[  ]+")
        fp = open(p_d_f, 'rb')
       
        #Extraire les coordonnées et les données de caractères du pdf
        for page in PDFPage.get_pages(fp):
            rsrcmgr = PDFResourceManager()
            laparams = LAParams()
            laparams.detect_vertical = True
            device = PDFPageAggregator(rsrcmgr, laparams=laparams)
            interpreter = PDFPageInterpreter(rsrcmgr, device)
            #Obtenez des coordonnées et des données de caractères à partir de PDF
            interpreter.process_page(page)
            layout = device.get_result() 
            
            #Créer un dictionnaire de coordonnées et de données
            d={}
            for node in layout:
                if isinstance(node, LTTextBox) or isinstance(node, LTTextLine):
                    y1 = node.bbox[3]
                    #S'il s'agit d'une table, les coordonnées de y1 sont dupliquées, donc une jointure de chaîne
                    if y1 in d:
                       d[y1] += "|" + node.get_text()
                    else:
                       d.update({y1 : node.get_text()})
            
            #Trier par coordonnée
            d2 = sorted(d.items(), key=lambda x: -x[0])
            
            #Se heurter à une corde
            text = ""
            for d0 in d2:
                 text += ddd[1]
            
            #Supprimer les sauts de ligne vides
            text = re.sub(space, "", text)
            l_text = [a for a in text.splitlines() if a != '']
            text = '\n'.join(l_text).replace('\n|', '|')     
            
            df.loc[cnt,["Phrase","numéro de page"]] = [text,cnt]
            cnt += 1
            
        fp.close()
        device.close()
         
        now = datetime.datetime.now()
        df["Mettre à jour la date et l'heure"] = now

        csv_path = p_d_f.replace('.pdf', '.csv')
        with open(csv_path, mode='w', encoding='cp932', errors='ignore', newline='\n') as f:
             df.to_csv(f,index=False)

if __name__ == "__main__":

  p_d_f = "En quelque sorte.pdf"
  con=converter()
  hoge=con.pdf_to_csv(p_d_f)

Je ne l'ai pas bien vérifié car je l'ai ajouté et soustrait de la dernière fois, mais quelque chose de similaire a fonctionné. Si vous obtenez une erreur, veuillez la corriger vous-même.

Recommended Posts

[Python] Suite - Convertir le texte PDF en CSV page par page
[Python] Convertir le texte PDF en CSV pour chaque page (2/24 postscript)
Comment ajouter des numéros de page à un fichier PDF (en Python)
Comment enregistrer une table récupérée par python en csv
Ajouter un numéro de page au PDF
Parler avec Python [synthèse vocale]
Écrire en csv avec Python
Convertir un PDF en documents par OCR
Convertir Markdown en PDF en Python
[Python] Ecrire dans un fichier csv avec Python
Sortie vers un fichier csv avec Python
Rejoignez CSV normalisé par les pandas Python pour faciliter la vérification
[Good By Excel] script python pour générer sql pour convertir csv en table
[Python] Comment convertir un fichier db en csv
Réintroduction aux décorateurs Python ~ Apprenons les décorateurs par type ~
Réponse à la sélection des débutants d'AtCoder par Python3
[Python] Convertit les délimiteurs de fichier csv en délimiteurs de tabulation
Fonction pour enregistrer les images par date [python3]
Je souhaite convertir une table convertie en PDF en Python en CSV
Convertir un PDF joint en courrier électronique au format texte
Lire Python csv et exporter vers txt
Livres recommandés par 3 types liés à Python
[Part1] Scraping avec Python → Organisez jusqu'à csv!
Python> Numéros de sortie de 1 à 100, 501 à 600> Pour csv
(Notes diverses) Modèle de mise à jour des données à partir de l'acquisition / traitement des données CSV par Python vers Excel
[python] Comment afficher les éléments de la liste côte à côte
Comment lire un fichier CSV avec Python 2/3
Grattage de la nourriture avec python et sortie en CSV
Résumé de la comparaison des bibliothèques pour générer des PDF avec Python
Télécharger le fichier texte sur le serveur de location avec ftp
Convertir un PDF en image (JPEG / PNG) avec Python
[Python] Conversion de DICOM en PNG ou CSV
tse --Introduction à l'éditeur de flux de texte en Python
Écriture de journaux dans un fichier CSV (Python, langage C)
Comment effacer les caractères générés par Python
PDF de la liste des magasins du buffet du petit-déjeuner COCO converti en CSV
[Python] Comment trier les instances par variables d'instance
Je souhaite vendre les produits que j'ai listés par python scraping Mercari
Exécutez Power Query en passant des arguments à Python
Mis à jour vers Python 2.7.9
CSV en Python
Page de référence Python
"Backport" vers python 2
[Keras] Mémo personnel pour classer les images par dossier [Python]
Liste des articles liés à l'optimisation par Python vers Docker
J'ai essayé de toucher un fichier CSV avec Python
Lisez le fichier xml en vous référant au didacticiel Python
Convertissez l'image au format .zip en PDF avec Python
Comment convertir un fichier JSON en fichier CSV avec Python Pandas
[Python] Changer l'entrée standard du clavier en fichier texte
[Python] Un mémo pour écrire du CSV verticalement avec Pandas
[Python-pptx] Afficher les informations de police PowerPoint au format csv avec python
Fusionner deux fichiers PDF page par page l'un avec l'autre
Script Python qui crée un fichier JSON à partir d'un fichier CSV
Comment lire un csv contenant uniquement des entiers en Python
Python Open CV a essayé d'afficher l'image sous forme de texte.
Comment lire du texte avec une entrée standard ou une spécification de nom de fichier comme cat en Python