Trouver des fichiers PDF en double par contenu

9

Certaines revues génèrent un PDF différent pour chaque téléchargement. APS, par exemple, stocke l'heure et l'adresse IP dans le PDF.

Ou il existe une version papier avec des hyperliens et une avec des références textuelles.

Comment est-il possible de trouver des téléchargements en double d'articles avec un contenu égal à 90% sur un système Linux en utilisant un logiciel open source?

J'ai pensé à convertir les fichiers PDF en texte brut dans un répertoire temporaire avec pdf2txt. Ensuite, je pourrais filtrer tous les noms de fichiers qui diff a bproduisent plus de x lignes. Mais ce n'est pas élégant du tout et échouera avec les publications numérisées. Les revues ne fournissent souvent pas de texte OCR pour les anciennes publications.

J'ai également essayé comparedans la suite ImageMagick, mais je ne pouvais pas gérer les fichiers PDF multipages avec cet outil.

diffpdf 2.1.1 fait un bon travail dans une interface graphique sur deux fichiers, mais je n'ai pas pu comprendre comment l'appliquer sur de nombreux fichiers, et les versions récentes ne sont disponibles sous aucune licence open source.

Jonas Stein
la source
1
Puisqu'il existe des approches très différentes parmi les réponses, il pourrait être bon d'être plus précis et de clarifier la question. Recherchez-vous maintenant un moyen robuste de comparer différents fichiers pdf, y compris des articles scientifiques, entre autres, ou essayez-vous de trouver une solution efficace et élégante pour comparer les articles de revues, où il suffit de vérifier si le titre ou le DOI correspondent?
inVader
Je cherche une solution similaire - maintenant j'utilise md5 qui est problématique lorsque chaque téléchargement enregistre l'heure et l'ip dans le pdf. Je travaille sur une solution avec imagemagick avec un script wrapper pour parcourir les pages (et éventuellement essayer de sauter la première page au cas où c'est l'en-tête ajouté par le journal). Je suis convaincu que c'est la solution la plus robuste possible. Vous savez que cela fonctionnera très bien car c'est la même méthode qu'une personne utilise pour comparer visuellement deux documents. Il est également complètement indépendant sur la façon dont le document est généré, seulement son apparence visuelle.
orion
Je dirais également qu'une comparaison d'une seule page est probablement suffisante - il est peu probable que deux documents soient différents si une seule page est la même. La notation blah.pdf[1]appellera la page souhaitée du document.
orion
Si vous avez vraiment besoin de comparer des fichiers PDF où l'un ou les deux sont basés sur la numérisation, je pense que vous ne pouvez pas éviter d'utiliser l'OCR. Bon nombre des approches suggérées ici ne résolvent donc pas vraiment le problème.
gogoud

Réponses:

4

Étant donné que différents éditeurs utilisent différentes méthodes de «marquage» des fichiers PDF, vous devez vous assurer de les comparer sans prendre en compte les marquages.

Vous avez également besoin d'une méthode efficace pour comparer un nouveau PDF à tous les PDF déjà téléchargés au cas où vous téléchargez à plusieurs reprises le même PDF et qu'il est par exemple marqué de l'IP et / ou de l'horodatage comme vous le suggérez. Vous ne voulez pas utiliser un mécanisme de comparaison chronophage qui compare chaque nouveau PDF avec de nombreux PDF déjà téléchargés

Vous avez besoin d'un utilitaire qui supprime chacun des marquages ​​possibles et génère un hachage des données restantes. Vous devrez conserver une table de hachage → nom de fichier, qui peut être dans un fichier simple, et si un hachage calculé est déjà dans le fichier, vous en avez un doublon (et supprimez-le ou faites tout ce qui est nécessaire) et si le hachage n'est pas encore là, vous ajoutez le hachage et le nom du fichier. Le fichier ressemblerait à quelque chose comme:

6fcb6969835d2db7742e81267437c432  /home/anthon/Downloads/explanation.pdf
fa24fed8ca824976673a51803934d6b9  /home/anthon/orders/your_order_20150320.pdf

Ce fichier est négligemment petit par rapport aux PDF d'origine. Si vous avez des millions de PDF, vous pouvez envisager de stocker ces données dans une base de données. Pour des raisons d'efficacité, vous souhaiterez peut-être inclure la taille du fichier et le nombre de pages ( pdfinfo | egrep -E '^Pages:' | grep -Eo '[0-9]*').


Ce qui précède pousse le problème à supprimer les marquages ​​et à générer le hachage. Si vous savez d'où vient le PDF lors de l'appel de la routine de génération de hachage (c'est-à-dire si vous effectuez les téléchargements par programme), vous pouvez affiner la génération de hachage en fonction de cela. Mais même sans cela, il existe plusieurs possibilités pour la génération de hachage:

  1. si les métadonnées pour le titre et l'auteur ne sont pas vides et n'incluent pas de chaînes non spécifiques comme "Acrobat" ou "PDF", vous pouvez générer le hachage en fonction uniquement des informations sur l'auteur et le titre. Utilisez pdfinfo -E file.pdf | grep -E '^(Author:)|(Title:) | md5sumpour obtenir le hachage. Vous pouvez également inclure le nombre de pages dans le calcul du hachage (' Pages:' dans la pdfinfosortie).
  2. si la règle précédente ne fonctionne pas et que le PDF contient des images, extrayez les images et générez un hachage sur les données d'image combinées. Si les images contiennent du texte dans le pied de page ou l'en-tête comme "Licensed to Joe User", supprimez un nombre X de lignes en haut ou en bas, avant de calculer le hachage. Si ces marquages ​​sont dans un gros texte d'arrière-plan grisé, cela ne fonctionnera bien sûr pas, sauf si vous filtrez les pixels qui ne sont pas totalement noirs (pour cela, vous pouvez les utiliser imagemagick). Vous pouvez utiliser pdfimagespour extraire les informations d'image dans un fichier temporaire.
  3. si les règles précédentes ne fonctionnent pas (car il n'y a pas d'images), vous pouvez utiliser pdftextpour extraire le texte, filtrer le marquage (si vous filtrez un peu trop, ce n'est pas un problème), puis générer le hachage en fonction de cette.

De plus, vous pouvez comparer si la taille du fichier de l'ancien fichier trouvé via le hachage et voir si se trouve dans certaines marges avec le nouveau fichier. La compression et les différences dans les chaînes (IP / horodatage) ne devraient entraîner qu'une différence de moins d'un pour cent.

Si vous connaissez la méthode que l'éditeur utilise pour déterminer le hachage, vous pouvez directement appliquer la "bonne" méthode de ce qui précède, mais même sans cela, vous pouvez vérifier les métadonnées et appliquer des heuristiques, ou déterminer le nombre d'images dans un fichier et comparez cela avec le nombre de pages (si elles sont proches, vous avez probablement un document composé de numérisations). pdftextsur les images numérisées, les PDF ont également une sortie reconnaissable.


Comme base de travail, j'ai créé un package python qui est sur bitbucket et / ou peut être installé à partir de PyPI en utilisant pip install ruamel.pdfdouble. Cela vous fournit la pdfdblcommande qui effectue la numérisation comme décrit ci-dessus sur les métadonnées, les images extraites ou le texte. Il ne filtre pas (encore) les marquages , mais le fichier Lisez-moi décrit les (deux) méthodes à améliorer pour l'ajouter.

Le fichier Lisezmoi inclus:

ruamel.pdfdouble

ce package fournit la pdfdblcommande:

pdfdbl scan dir1 dir2

Cela parcourra les répertoires fournis en argument et pour les fichiers PDF trouvés, créez un hachage basé sur (dans l'ordre):

  • métadonnées si uniques
  • images si le nombre d'images
  • texte

Cela suppose que pdfinfo, pdfimages et pdftotext` du paquet poppler-utils sont disponibles.

Une "base de données" est en train de se constituer, par ~/.config/pdfdbl/pdf.lstrapport à laquelle d'autres analyses sont testées.

Suppression des marquages

Il ruamel/pdfdouble/pdfdouble.pyexiste deux méthodes qui peuvent être améliorées pour filtrer les marquages ​​dans le PDF qui les rendent moins uniques et font pratiquement les mêmes fichiers pour avoir des hachages différents.

Pour le texte, la méthode PdfData.filter_for_markingdoit être étendue pour supprimer et marquer de la chaîne qui est ses arguments et retourner le résultat.

Pour les images numérisées, la méthode PdfData.process_image_and_updatedoit être améliorée, par exemple en coupant les lignes X inférieures et supérieures des images, et en supprimant tout texte d'arrière-plan gris en définissant tous les pixels noirs sur blanc. Cette fonction doit mettre à jour le hachage transmis à l'aide de la .update()méthode transmettant les données filtrées.

Restrictions

La "base de données" actuelle ne peut pas gérer les chemins d'accès qui contiennent des retours à la ligne

Cet utilitaire est actuellement Python 2.7 uniquement.


Les parties de chaîne conformes à IP peuvent être remplacées par le remodule de Python :

import re
IPre = re.compile("(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}"
              "([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])")

x = IPre.sub(' ', 'abcd 132.234.0.2 ghi')
assert x == 'abcd   ghi'
Anthon
la source
Dans le passé, j'ai également utilisé le paquet python pdfrwpour extraire les métadonnées, mais cela ne peut pas gérer les fichiers PDF chiffrés, où c'est pdfinfopossible.
Anthon
2

Je donnerais pdftotextune autre chance, au moins pour les fichiers PDF de votre collection qui contiennent réellement du texte (sinon vous auriez besoin d'exécuter l'OCR), en utilisant un meilleur outil pour traiter la sortie.

Une fois que vous avez votre sortie de texte (sale), exécutez-la via un programme conçu pour déterminer les similitudes (plutôt que diffles différences ligne par ligne, ce qui serait un chemin rapide vers la folie).

Considérez quelque chose comme String :: Similarity de perl ou le programme simhash (qui est disponible dans Debian mais pas Fedora / RHEL).

Adam Katz
la source
2

Les PDF contiennent des métadonnées et je viens de vérifier un certain nombre d'articles liés à la physique de différents éditeurs et ils ont tous au moins l'attribut "Titre". Pour certains, le titre est le titre réel de la publication, pour certains, il contient le DOI ou des identifiants similaires. Quoi qu'il en soit, chaque article que j'ai vérifié contient le titre, et c'est toujours quelque chose d'unique à la publication donnée.

Vous pouvez utiliser pdftkpour accéder aux métadonnées des PDF et les comparer. Pour votre objectif, cela devrait certainement être suffisant et beaucoup plus rapide que pdftotextsi les performances sont un problème. Dans le cas où un document ne devrait vraiment pas avoir de métadonnées de titre, vous pourriez toujours y revenir pdftotext.

Pour vider toutes les métadonnées dans un fichier texte (ou stdout) pour un traitement ultérieur, utilisez

pdftk <PDF> dump_data output <TEXTFILE>

ou reportez-vous au manuel pour plus d'options.

Si vous voulez essayer ImageMagick de comparemais plusieurs pages posent un problème, vous pouvez également utiliser pdftkpour extraire des pages uniques et comparer tous séparément (peut - être juste un seul comparait suffit, cependant).

Voici un extrait de code qui utilise cette approche pour créer une diffsortie PDF semblable à celle des fichiers PDF multipages: https://gist.github.com/mpg/3894692

envahisseur
la source
1

Avez-vous examiné le contenu PDF Comparer ? Il existe des options de ligne de commande qui devraient vous permettre d'automatiser le processus.

Vous pouvez exécuter une sorte de logique sur le journal des différences qu'il crée pour voir à quel point ils sont similaires.

À défaut, vous pourriez essayer de diviser temporairement les PDF en plusieurs fichiers et de les comparer de cette façon. Vous auriez probablement encore des doublons de cette façon. Un PDF peut simplement avoir une page vierge supplémentaire ou quelque chose qui ferait comparer toutes les pages suivantes comme étant complètement différentes.

Bratchley
la source
Peut-être que les deux versions les plus chères de ce programme à code source fermé peuvent faire le travail. Je préférerais une solution open source, même si elle n'a pas besoin d'être gratuite.
Jonas Stein
1

Suite à une humble contribution à la discussion (réponse partielle):

Après la conversion en texte, j'utiliserais ce qui suit pour calculer la smilarité du fichier (basé sur la différence de mots):

wdiff -s -123 file1.txt file2.txt |    ## word difference statistics (1)
     grep -Po '(\d+)(?=% common)' |    ## 
     awk '{a+=$1}END{print a/2}'       ## (2)

(1) produit un résultat comme

file1.txt: 36 words  33 92% common  3 8% deleted  0 0% changed
file2.txt: 35 words  33 94% common  2 6% inserted  0 0% changed

(2) = 93

JJoao
la source
1

J'ai un script qui regarde un pdf et essaie d'abord d'extraire du texte en utilisant pdftotext, mais si cela échoue (comme ce sera le cas avec un document numérisé), il utilise ghostscript pour transformer un pdf numérisé de plusieurs pages en une série de fichiers png, puis utilise tesseract pour convertir cette série en un seul fichier texte. Si la numérisation est de qualité suffisante, elle fait un très bon travail. Il serait simple d'ajouter du code comparant le texte entre les fichiers mais je n'ai pas eu cette exigence.

ghostscript et tesseract sont tous deux open source et fonctionnent à partir de la ligne de commande.

gogoud
la source
Vous pouvez extraire directement des images numérisées à l'aide pdfimagesdu package poppler sans perte supplémentaire de qualité que vous pourriez obtenir avec le rendu via ghostscript (ce qui influence négativement tout OCR que vous voulez faire).
Anthon
@Anthon merci d'avoir souligné cela, mais fait sûrement pdfimagesla même chose que ghostscript ( gs) ici, c'est-à-dire extraire des images de pdf en jpg / png. Pourquoi est-ce mieux que ça gs?
gogoud
Le rendu que ghostscript fait déforme les pixels des images à moins que toutes les numérisations aient la même résolution (ce n'est pas le cas par exemple si les bords d'espaces blancs ont été supprimés) et seulement si vous effectuez le rendu exactement à la même résolution que les images utilisent
Anthon
@Anthon Intéressant, j'ai fait quelques tests. Les résultats sont très similaires mais il semble que gs/ tesseract(format intermédiaire png) fonctionne légèrement mieux que pdfimages/ tesseract(format intermédiaire pbm). pdfimagesest plus rapide cependant.
gogoud
0

Je proposerais Perl comme solution. Il y a un module appelé CAM::PDFqui vous permet d'extraire ... du contenu PDF.

Cela fonctionne un peu comme ceci:

#!/usr/bin/perl

use strict;
use warnings;

use CAM::PDF;

my $file = 'sample.pdf';

my $pdf = CAM::PDF->new($file);

my $word_count = 0;
for my $pagenum ( 1 .. $pdf->numPages ) {
    my $page_text = $pdf->getPageText($pagenum) );
    print $page_text; 
}

Vous pouvez extraire le texte et le comparer.

Pour les documents numérisés uniquement - c'est beaucoup plus difficile, mais en supposant qu'ils utilisent les mêmes images de base (par exemple, ils ne les ont pas numérisés séparément), vous pouvez probablement utiliser:

#!/usr/bin/perl

use strict;
use warnings;

use CAM::PDF;
use CAM::PDF::Renderer::Images;
use Data::Dumper; 

my $file = 'sample.pdf';

my $pdf = CAM::PDF->new($file);

my $word_count = 0;
for my $pagenum ( 1 .. $pdf->numPages ) {
    my $content =  $pdf->getPageText($pagenum);
    my $page = $pdf->getPageContentTree($pagenum);
    my $gs = $page->findImages();
    my @imageNodes = @{$gs->{images}};
    print Dumper \@imageNodes;

    print Dumper \$gs;
}

Je ne l'ai pas particulièrement bien testé, car je n'ai pas vos documents sources. Je pense que cette approche devrait faire l'affaire - vous ne comparez pas le contenu réel de l'image, car ... eh bien, c'est vraiment difficile. Mais vous devriez pouvoir reconnaître des images similaires à partir des métadonnées.

Pour des PDF identiques avec des métadonnées différentes, alors quelque chose de simple comme hacher le contenu du texte et les métadonnées de l'image devrait faire l'affaire.

Sobrique
la source
-1

Il existe une application Linux, appelée recoll . Il peut effectuer la tâche, mais uniquement pour les fichiers PDF avec couche de texte.

annndrey
la source
2
Il me recollsemble que c'est un moteur de recherche de bureau. Je ne pouvais pas voir comment l'utiliser pour trouver des doublons.
Jonas Stein
1
recollutilise pdftotextpour gérer les fichiers PDF, ce que l'OP essaie d'éviter ici.
John WH Smith