80 votes

Analyse des fichiers PDF (surtout avec des tables) avec PDFBox

Je dois analyser un fichier PDF qui contient des données tabulaires. J'utilise PDFBox pour extraire le texte du fichier afin d'analyser le résultat (String) plus tard. Le problème est que l'extraction de texte ne fonctionne pas comme prévu pour les données tabulaires. Par exemple, j'ai un fichier qui contient un tableau comme celui-ci (7 colonnes : les deux premières ont toujours des données, une seule colonne Complexité a des données, une seule colonne Financement a des données) :

+----------------------------------------------------------------+
| AIH | Valeur | Complexité                    | Financement     |
|     |       | Moyen | Élevé | Non applicable  | MAC/Autre | FAE |
+----------------------------------------------------------------+
| xyz | 12.43 | 12.34   |      |                 | 12.34     |     |
+----------------------------------------------------------------+
| abc | 1.56  |        | 1.56 |                 |           | 1.56|
+----------------------------------------------------------------+

Ensuite j'utilise PDFBox :

PDDocument document = PDDocument.load(pathToFile);
PDFTextStripper s = new PDFTextStripper();
String content = s.getText(document);

Ces deux lignes de données seraient extraites comme ceci :

xyz 12.43 12.4312.43
abc 1.56 1.561.56

Il n'y a pas d'espaces entre les deux derniers nombres, mais ce n'est pas le plus gros problème. Le problème est que je ne sais pas ce que représentent les deux derniers nombres : Moyen, Élevé, Non applicable ? MAC/Autre, FAE ? Je n'ai pas la relation entre les nombres et leurs colonnes.

Il n'est pas nécessaire pour moi d'utiliser la bibliothèque PDFBox, donc une solution qui utilise une autre bibliothèque est acceptable. Ce que je veux c'est pouvoir analyser le fichier et savoir ce que chaque nombre analysé signifie.

11 votes

Bonne chance... Je suis moi-même dans l'enfer du PDF, et complètement dégoûté par ce format à ce stade.

27 votes

PDF était conçu pour être un format d'affichage de sortie et non pour l'extraction. Accusez les utilisateurs, pas le format.

0 votes

Si le PDF est de mise en page fixe, il existe d'autres façons d'extraire les données des colonnes. Je viens de créer un outil pour extraire le texte PDF des positions de champs fixes sur un formulaire. Ce serait intéressant de voir le fichier PDF auquel Matheus fait référence.

20voto

purecharger Points 840

Vous devrez concevoir un algorithme pour extraire les données dans un format utilisable. Peu importe la bibliothèque PDF que vous utilisez, vous devrez le faire. Les caractères et les graphiques sont dessinés par une série d'opérations de dessin à état, c'est-à-dire déplacer à cette position à l'écran et dessiner le glyphe pour le caractère 'c'.

Je vous suggère de prolonger org.apache.pdfbox.pdfviewer.PDFPageDrawer et de remplacer la méthode strokePath. À partir de là, vous pouvez intercepter les opérations de dessin des segments de lignes horizontales et verticales et utiliser ces informations pour déterminer les positions colonne et rangée de votre tableau. Ensuite, il suffit de mettre en place des régions de texte et de déterminer quels chiffres/lettres/caractères sont dessinés dans quelle région. Comme vous connaissez la disposition des régions, vous pourrez dire à quelle colonne appartient le texte extrait.

Aussi, la raison pour laquelle vous n'avez peut-être pas d'espaces entre du texte visuellement séparé est que très souvent, un caractère d'espace n'est pas dessiné par le PDF. À la place, la matrice de texte est mise à jour et une commande de dessin pour 'déplacer' est émise pour dessiner le caractère suivant et une "largeur d'espace" à part du précédent.

Bonne chance.

0 votes

Ce outil semble faire quelque chose comme ci-dessus, et il y a du code source disponible jpedal.org/support_egTZ.php

0 votes

J'ai récemment fait quelque chose de similaire, sauf que j'ai dû composer avec plusieurs lignes de texte. Jetez également un œil à l'ensemble de classes ExtractText pour savoir comment extraire le texte réel une fois que vous avez les colonnes et les lignes. Sur une autre note, j'ai eu des problèmes pour obtenir les lignes correctes, mais j'ai pu ajuster en supposant une nouvelle ligne lorsque je suis revenu aux colonnes.

0 votes

@deterb Comment avez-vous géré le texte multiligne?

17voto

Emerson Farrugia Points 3085

Vous pouvez extraire du texte par zone dans PDFBox. Voir le fichier d'exemple ExtractByArea.java, dans l'artefact pdfbox-examples si vous utilisez Maven. Un extrait ressemble à ceci :

   PDFTextStripperByArea stripper = new PDFTextStripperByArea();
   stripper.setSortByPosition( true );
   Rectangle rect = new Rectangle( 464, 59, 55, 5);
   stripper.addRegion( "class1", rect );
   stripper.extractRegions( page );
   String string = stripper.getTextForRegion( "class1" );

Le problème est d'obtenir d'abord les coordonnées. J'ai eu du succès en étendant le TextStripper normal, en remplaçant processTextPosition(TextPosition text) et en imprimant les coordonnées de chaque caractère pour déterminer où ils se trouvent dans le document.

Mais il y a une façon beaucoup plus simple, en particulier si vous êtes sur Mac. Ouvrez le PDF dans Aperçu, ⌘I pour afficher l'Inspecteur, choisissez l'onglet Recadrer et assurez-vous que les unités sont en points, dans le menu Outils choisissez la Sélection rectangulaire, et sélectionnez la zone d'intérêt. Si vous sélectionnez une zone, l'inspecteur vous montrera les coordonnées, que vous pouvez arrondir et introduire dans les arguments du constructeur Rectangle. Vous devez simplement confirmer où se trouve l'origine, en utilisant la première méthode.

2 votes

Belle, solution simple pour quand les PDF ont une mise en page fixe! Donnerait un autre upvote (si je pouvais!) pour le truc d'utiliser Aperçu sur macOS. Rend l'extraction vraiment facile.

11voto

impeto Points 73

Il est peut-être trop tard pour ma réponse, mais je pense que ce n'est pas si difficile. Vous pouvez étendre la classe PDFTextStripper et remplacer les méthodes writePage() et processTextPosition(...). Dans votre cas, je suppose que les en-têtes de colonnes sont toujours les mêmes. Cela signifie que vous connaissez la coordonnée x de chaque en-tête de colonne et vous pouvez comparer la coordonnée x des chiffres à celles des en-têtes de colonne. S'ils sont assez proches (vous devez tester pour décider à quelle distance), alors vous pouvez dire que ce nombre appartient à cette colonne.

Une autre approche serait d'intercepter le vecteur "charactersByArticle" après que chaque page soit écrite:

@Override
public void writePage() throws IOException {
    super.writePage();
    final Vector> pageText = getCharactersByArticle();
    //maintenant vous avez tous les caractères sur cette page
    //pour faire ce que vous voulez avec eux
}

En connaissant vos colonnes, vous pouvez comparer les coordonnées x pour décider à quelle colonne chaque chiffre appartient.

La raison pour laquelle vous n'avez pas d'espaces entre les chiffres est parce que vous devez définir la chaîne de séparateur de mots.

J'espère que cela vous sera utile ou à d'autres qui pourraient essayer des choses similaires.

4voto

scott Points 774

J'ai eu un succès décent avec l'analyse des fichiers texte générés par l'utilitaire pdftotext (sudo apt-get install poppler-utils).

File convertPdf() throws Exception {
    File pdf = new File("mypdf.pdf");
    String outfile = "mytxt.txt";
    String proc = "/usr/bin/pdftotext";
    ProcessBuilder pb = new ProcessBuilder(proc,"-layout",pdf.getAbsolutePath(),outfile); 
    Process p = pb.start();

    p.waitFor();

    return new File(outfile);
}

1 votes

Pour les utilisateurs de Windows, téléchargez votre fichier exe depuis : foolabs.com/xpdf/download.html pointez la variable proc vers le fichier pdftotext.exe. Supprimez le type de retour et le mot-clé return de la fonction si elle est exécutée dans la fonction principale.

2voto

Todd Owen Points 4477

Extraire des données d'un PDF est forcément source de problèmes. Les documents sont-ils créés par le biais d'un processus automatique ? Si c'est le cas, vous pourriez envisager de convertir les PDF en PostScript non compressé (essayez pdf2ps) et voir si le PostScript contient une sorte de motif régulier que vous pouvez exploiter.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X