Après précédent, j'ai pensé que cette réparation était nécessaire, donc c'est une simple continuation.
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.
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.
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.
① 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.
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é!"
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.
text = ""
for d0 in d2:
text += d0[1]
C'est juste rond et rond.
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é.
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