Suchen Sie nach doppelten PDF-Dateien nach Inhalt

9

Einige Zeitschriften generieren für jeden Download ein anderes PDF. APS speichert beispielsweise die Zeit und die IP-Adresse im PDF.

Oder es gibt eine Papierversion mit Hyperlinks und eine mit Textreferenzen.

Wie ist es möglich, doppelte Downloads von Papieren mit 90% gleichem Inhalt auf einem Linux-System mithilfe von Open-Source-Software zu finden?

Ich habe darüber nachgedacht, die PDF-Dateien in einfachen Text in einem temporären Verzeichnis mit zu konvertieren pdf2txt. Dann könnte ich alle Dateinamen filtern, was diff a bmehr als x Zeilen ergibt. Dies ist jedoch überhaupt nicht elegant und schlägt bei gescannten Veröffentlichungen fehl. Zeitschriften bieten häufig keinen OCR-Text für alte Veröffentlichungen.

Ich habe es auch comparein der ImageMagick-Suite versucht, konnte jedoch mit diesem Tool keine mehrseitigen PDF-Dateien verarbeiten.

diffpdf 2.1.1 leistet gute Arbeit in einer GUI für zwei Dateien, aber ich konnte nicht herausfinden, wie es auf viele Dateien angewendet werden kann, und neuere Versionen sind unter keiner Open Source-Lizenz verfügbar.

Jonas Stein
quelle
1
Da es bei den Antworten sehr unterschiedliche Ansätze gibt, kann es sinnvoll sein, genauer zu sein und die Frage zu klären. Suchen Sie jetzt nach einer zuverlässigen Methode zum Vergleichen verschiedener PDF-Dateien, einschließlich wissenschaftlicher Arbeiten, oder suchen Sie nach einer effizienten, eleganten Lösung zum Vergleichen von Zeitschriftenartikeln, bei der es völlig ausreicht, nur zu überprüfen, ob Titel oder DOI übereinstimmen.
InVader
Ich suche nach einer ähnlichen Lösung - jetzt verwende ich md5, was problematisch ist, wenn jeder Download Zeit und IP im PDF aufzeichnet. Ich arbeite an einer Lösung mit imagemagick mit einem Wrapper-Skript zum Durchlaufen von Seiten (und versuche möglicherweise, die erste Seite zu überspringen, falls es sich um den vom Journal hinzugefügten Header handelt). Ich bin sehr zuversichtlich, dass dies die robusteste Lösung ist . Sie wissen, dass es sehr gut funktioniert, da es dieselbe Methode ist, die eine Person beim visuellen Vergleich zweier Dokumente verwendet. Es ist auch völlig unabhängig von der Art und Weise, wie das Dokument erstellt wird, nur von seinem visuellen Erscheinungsbild.
Orion
Ich würde auch sagen, dass ein Vergleich einer einzelnen Seite wahrscheinlich ausreicht - es ist unwahrscheinlich, dass zwei Dokumente unterschiedlich sind, wenn eine Seite gleich ist. Die Notation blah.pdf[1]ruft eine gewünschte Seite aus dem Dokument auf.
Orion
Wenn Sie wirklich PDFs vergleichen müssen, bei denen eines oder beide auf dem Scannen basieren, können Sie die Verwendung von OCR nicht vermeiden. Viele der hier vorgeschlagenen Ansätze lösen das Problem daher nicht wirklich.
Gogoud

Antworten:

4

Da verschiedene Verlage unterschiedliche Methoden zum "Markieren" der PDFs verwenden, müssen Sie sicherstellen, dass Sie sie vergleichen, ohne die Markierungen zu berücksichtigen.

Sie benötigen auch eine effiziente Methode, um ein neues PDF mit allen bereits heruntergeladenen PDFs zu vergleichen, falls Sie wiederholt dasselbe PDF herunterladen und es z. B. mit der IP und / oder dem Datums- / Zeitstempel gekennzeichnet ist, wie Sie vorschlagen. Sie möchten keinen zeitaufwändigen Vergleichsmechanismus verwenden, der jedes neue PDF mit vielen bereits heruntergeladenen PDFs vergleicht

Was Sie brauchen, ist ein Dienstprogramm, das jede der möglichen Markierungen entfernt und einen Hash der verbleibenden Daten generiert. Sie müssen eine Hash → Dateinamenzuordnung behalten, die sich in einer einfachen Datei befinden kann. Wenn sich bereits ein berechneter Hash in der Datei befindet, haben Sie ein Duplikat (und löschen es oder tun, was auch immer erforderlich ist) und wenn der Hash noch nicht vorhanden ist Dort fügen Sie den Hash und den Dateinamen hinzu. Die Datei würde ungefähr so ​​aussehen:

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

Diese Datei ist im Vergleich zu den Original-PDFs fahrlässig klein. Wenn Sie Millionen von PDFs haben, können Sie diese Daten in einer Datenbank speichern. Aus Effizienzgründen möchten Sie möglicherweise die Dateigröße und die Anzahl der Seiten dort einfügen ( pdfinfo | egrep -E '^Pages:' | grep -Eo '[0-9]*').


Das Obige führt dazu, dass die Markierungen entfernt und der Hash generiert werden. Wenn Sie wissen, woher das PDF stammt, wenn Sie die Hash-Generierungsroutine aufrufen (dh wenn Sie die Downloads programmgesteuert durchführen), können Sie die Hash-Generierung basierend darauf optimieren. Aber auch ohne das gibt es mehrere Möglichkeiten für die Hash-Generierung:

  1. Wenn die Metadaten für Titel und Autor nicht leer sind und keine unspezifischen Zeichenfolgen wie "Acrobat" oder "PDF" enthalten, können Sie den Hash nur anhand der Autoren- und Titelinformationen generieren. Verwenden Sie pdfinfo -E file.pdf | grep -E '^(Author:)|(Title:) | md5sum, um den Hash zu erhalten. Sie können auch die Anzahl der Seiten in die Berechnung des Hashs einbeziehen (' Pages:' in der pdfinfoAusgabe).
  2. Wenn die vorherige Regel nicht funktioniert und die PDF-Datei Bilder enthält, extrahieren Sie die Bilder und generieren Sie einen Hash für die kombinierten Bilddaten. Wenn die Bilder jemals Text in der Fußzeile oder in der Kopfzeile enthalten, z. B. "Lizenziert für Joe-Benutzer", entfernen Sie eine X-Anzahl von Zeilen oben oder unten, bevor Sie den Hash berechnen. Wenn sich diese Markierungen in einem grau hinterlegten Text mit großen Buchstaben befinden, funktioniert dies natürlich nicht, es sei denn, Sie filtern Pixel heraus, die nicht vollständig schwarz sind (für die Sie sie verwenden könnten imagemagick). Sie können pdfimagesdie Bildinformationen in eine temporäre Datei extrahieren.
  3. Wenn die vorherigen Regeln nicht funktionieren (da keine Bilder vorhanden sind), können Sie pdftextden Text extrahieren, die Markierung herausfiltern (wenn Sie ein wenig zu viel herausfiltern, ist dies kein Problem) und dann den Hash basierend auf generieren Das.

Außerdem können Sie vergleichen, ob die Dateigröße der alten Datei, die über den Hash gefunden wurde, mit der neuen Datei innerhalb bestimmter Grenzen liegt. Komprimierung und ifferences in Zeichenfolgen (IP / Datums- / Zeitstempel) sollten nur zu einem Unterschied von weniger als einem Prozent führen.

Wenn Sie die Methode kennen, die der Herausgeber bei der Ermittlung des Hashs verwendet, können Sie die oben beschriebene "richtige" Methode direkt anwenden. Auch ohne diese Methode können Sie nach Metadaten suchen und einige Heuristiken anwenden oder die Anzahl der Bilder in einer Datei bestimmen und vergleichen Sie das mit der Anzahl der Seiten (wenn sie geschlossen sind, haben Sie wahrscheinlich ein Dokument, das aus Scans besteht). pdftextBei gescannten Bildern haben PDFs auch eine erkennbare Ausgabe.


Als Grundlage für die Arbeit habe ich ein Python-Paket erstellt, das sich auf Bitbucket befindet und / oder mit PyPI installiert werden kann pip install ruamel.pdfdouble. Auf diese Weise erhalten Sie den pdfdblBefehl, der das Scannen wie oben beschrieben für Metadaten, extrahierte Bilder oder Text ausführt. Es führt keine Filterung von Markierungen (noch) nicht , aber die readme beschrieben , die (zwei) Methoden zu verbessern , das zu tun hinzuzufügen.

Die mitgelieferte Readme:

ruamel.pdfdouble

Dieses Paket enthält den folgenden pdfdblBefehl:

pdfdbl scan dir1 dir2

Dadurch werden die als Argument angegebenen Verzeichnisse durchsucht und für die gefundenen PDF-Dateien ein Hash erstellt, der auf (in der Reihenfolge) basiert:

  • Metadaten, falls eindeutig
  • Bilder, wenn die Anzahl der Bilder
  • Text

Dies setzt voraus, dass pdfinfo, pdfimages und pdftotext` aus dem poppler-utils-Paket verfügbar sind.

Es wird eine "Datenbank" aufgebaut, in ~/.config/pdfdbl/pdf.lstder weitere Scans getestet werden.

Markierungen entfernen

Es ruamel/pdfdouble/pdfdouble.pygibt zwei Methoden, die verbessert werden können, um Markierungen in der PDF-Datei herauszufiltern, die sie weniger eindeutig machen und praktisch dieselben Dateien mit unterschiedlichen Hashes erstellen.

Für Text sollte die Methode PdfData.filter_for_markingerweitert werden, um Markierungen aus der Zeichenfolge, die ihre Argumente sind, zu entfernen und das Ergebnis zurückzugeben.

Bei gescannten Bildern muss die Methode PdfData.process_image_and_updateverbessert werden, z. B. indem die unteren und oberen X-Linien der Bilder abgeschnitten werden und grauer Hintergrundtext entfernt wird, indem alle schwarzen Pixel auf Weiß gesetzt werden. Diese Funktion muss den übergebenen Hash mithilfe der .update()in den gefilterten Daten übergebenen Methode aktualisieren .

Beschränkungen

Die aktuelle "Datenbank" kann keine Pfade verarbeiten, die Zeilenumbrüche enthalten

Dieses Dienstprogramm ist derzeit nur Python 2.7.


IP-konforme Stringparts können durch das Python- reModul ersetzt werden:

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
quelle
In der Vergangenheit habe ich das Python-Paket auch pdfrwzum Extrahieren von Metadaten verwendet, aber das kann keine verschlüsselten PDF-Dateien verarbeiten, wo dies möglich pdfinfoist.
Anthon
2

Ich würde eine pdftotextweitere Chance geben, zumindest für die PDFs in Ihrer Sammlung, die tatsächlich Text enthalten (andernfalls müssten Sie OCR ausführen), und ein besseres Tool verwenden, um die Ausgabe zu verarbeiten.

Sobald Sie Ihre (schmutzige) Textausgabe haben, führen Sie sie durch ein Programm, mit dem Ähnlichkeiten ermittelt werden sollen (und nicht diffdie zeilenweisen Unterschiede, die ein schneller Weg zum Wahnsinn wären).

Betrachten Sie etwas wie String :: Similarity des Perls oder das Simhash- Programm (das in Debian, aber nicht in Fedora / RHEL verfügbar ist).

Adam Katz
quelle
2

Die PDFs enthalten Metadaten, und ich habe gerade eine Reihe von physikbezogenen Artikeln verschiedener Verlage überprüft, und alle haben mindestens das Attribut "Titel". Für einige ist der Titel der eigentliche Titel der Veröffentlichung, für einige enthält er den DOI oder ähnliche Bezeichner. Wie auch immer, jedes Papier, das ich überprüft habe, enthält den Titel, und es ist immer etwas Einzigartiges für die jeweilige Veröffentlichung.

Sie können pdftkdamit auf die Metadaten der PDFs zugreifen und diese vergleichen. Für Ihren Zweck sollte dies auf jeden Fall ausreichen und ist viel schneller, als pdftotextwenn die Leistung ein Problem darstellt. Für den Fall, dass ein Papier wirklich keine Titelmetadaten enthalten sollte, auf die Sie dennoch zurückgreifen können pdftotext.

Zum Speichern aller Metadaten in einer Textdatei (oder stdout) zur weiteren Verarbeitung

pdftk <PDF> dump_data output <TEXTFILE>

Weitere Informationen finden Sie im Handbuch.

Wenn Sie ImageMagicks ausprobieren möchten , compareaber mehrere Seiten ein Problem verursachen, können Sie auch pdftkeinzelne Seiten extrahieren und alle separat vergleichen (möglicherweise reicht es jedoch aus, nur eine einzelne Seite zu vergleichen).

Hier ist ein Codefragment, das diesen Ansatz verwendet, um eine diffähnliche PDF-Ausgabe für mehrseitige PDFs zu erstellen : https://gist.github.com/mpg/3894692

Eindringling
quelle
1

Haben Sie sich mit PDF Content Comparer befasst ? Es gibt Befehlszeilenoptionen, mit denen Sie den Prozess automatisieren können.

Sie können eine Art Logik für das Differenzprotokoll ausführen, um zu sehen, wie ähnlich sie sind.

Andernfalls können Sie versuchen , die PDFs vorübergehend in mehrere Dateien aufzuteilen und auf diese Weise zu vergleichen. Auf diese Weise hätten Sie wahrscheinlich immer noch Duplikate. Eine PDF-Datei enthält möglicherweise nur eine zusätzliche leere Seite oder etwas, das dazu führt, dass alle nachfolgenden Seiten als völlig unterschiedlich verglichen werden.

Bratchley
quelle
Möglicherweise sind die beiden teuersten Versionen dieses Closed-Source-Programms für diese Aufgabe geeignet. Ich würde eine Open Source-Lösung bevorzugen, obwohl sie nicht kostenlos sein muss.
Jonas Stein
1

Nach einem bescheidenen Beitrag zur Diskussion (Teilantwort):

Nach der Konvertierung in Text würde ich Folgendes verwenden, um die (wortdifferenzbasierte) Dateiähnlichkeit zu berechnen:

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

(1) ergibt ein Ergebnis wie

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
quelle
1

Ich habe ein Skript, das sich ein PDF ansieht und zuerst versucht, Text mit zu extrahieren. pdftotextWenn dies jedoch fehlschlägt (wie bei einem gescannten Dokument), verwendet es Ghostscript , um ein mehrseitig gescanntes PDF in eine Reihe von PNG-Dateien umzuwandeln und dann verwendet tesseract , um diese Reihe in eine einzelne Textdatei zu konvertieren. Wenn der Scan von ausreichender Qualität ist, macht er einen ziemlich guten Job. Es wäre unkompliziert, Code hinzuzufügen, der den Text zwischen Dateien vergleicht, aber ich hatte diese Anforderung nicht.

Ghostscript und Tesseract sind beide Open Source und funktionieren über die Befehlszeile.

gogoud
quelle
Sie können gescannte Bilder direkt pdfimagesaus dem Poppler-Paket extrahieren, ohne dass zusätzliche Qualitätsverluste beim Rendern durch Ghostscript auftreten (was sich negativ auf die gewünschte OCR auswirkt).
Anthon
@Anthon, danke, dass du darauf hingewiesen hast, aber sicherlich pdfimagesgenau das Gleiche wie Ghostscript ( gs), dh Bilder aus PDF nach JPG / PNG extrahieren. Warum ist das besser als gs?
Gogoud
Das Rendern, das Ghostscript ausführt, verzerrt die Pixel der Bilder, es sei denn, alle Scans haben dieselbe Auflösung (nicht der Fall, z. B. wenn Leerzeichen entfernt wurden) und nur dann, wenn Sie mit genau derselben Auflösung rendern, die die Bilder verwenden
Anthon
@Anthon Interessant, ich habe ein wenig getestet. Die Ergebnisse sind sehr ähnlich, aber es scheint, dass gs/ tesseract(png-Zwischenformat) etwas besser funktioniert als pdfimages/ tesseract(pbm-Zwischenformat). pdfimagesist aber schneller.
Gogoud
0

Ich würde Perl als Lösung anbieten. Es gibt ein Modul namens CAM::PDF, mit dem Sie ... PDF-Inhalte extrahieren können.

Es funktioniert ein bisschen so:

#!/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; 
}

Sie können den Text extrahieren und vergleichen.

Nur für gescannte Dokumente - es ist viel schwieriger, aber wenn sie dieselben Basisbilder verwenden (z. B. nicht separat gescannt haben), können Sie wahrscheinlich Folgendes verwenden:

#!/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;
}

Ich habe es nicht besonders gut getestet, weil ich Ihre Quelldokumente nicht habe. Ich denke, dieser Ansatz sollte den Trick machen - Sie vergleichen nicht den tatsächlichen Bildinhalt, weil ... nun, das ist wirklich schwierig. Sie sollten jedoch in der Lage sein, ähnliche Bilder anhand der Metadaten zu erkennen.

Bei identischen PDFs mit unterschiedlichen Metadaten sollte etwas Einfaches wie das Hashing des Textinhalts und der Bildmetadaten ausreichen.

Sobrique
quelle
-1

Es gibt eine Linux-Anwendung namens recoll . Es kann die Aufgabe ausführen, jedoch nur für PDFs mit Textebene.

Annndrey
quelle
2
Mir recollscheint eine Desktop-Suchmaschine zu sein. Ich konnte nicht sehen, wie man damit Duplikate findet.
Jonas Stein
1
recollverwendet pdftotext, um PDFs zu verarbeiten, was das OP hier zu vermeiden versucht.
John WH Smith