Znajdź zduplikowane pliki PDF według zawartości


9

Niektóre czasopisma generują inny plik PDF dla każdego pobrania. Na przykład APS przechowuje czas i adres IP w pliku PDF.

Lub istnieje wersja papierowa z hiperłączami i wersja z referencjami tekstowymi.

Jak można znaleźć podwójne pliki do pobrania z 90% równej zawartości w systemie Linux przy użyciu oprogramowania typu open source?

Myślałem o konwersji plików PDF na zwykły tekst w katalogu tymczasowym za pomocą pdf2txt. Następnie mógłbym filtrować wszystkie nazwy plików, co diff a bdaje więcej niż x linii. Ale to wcale nie jest eleganckie i nie powiedzie się w przypadku zeskanowanych publikacji. Czasopisma często nie zawierają tekstu OCR dla starych publikacji.

Próbowałem również comparew pakiecie ImageMagick, ale nie mogłem obsługiwać wielostronicowych plików PDF za pomocą tego narzędzia.

diffpdf 2.1.1 działa dobrze w GUI na dwóch plikach, ale nie mogłem wymyślić, jak zastosować go do wielu plików, a ostatnie wersje nie są dostępne na żadnej licencji typu open source.


1
Ponieważ odpowiedzi są bardzo odmienne, dobrze byłoby sprecyzować i wyjaśnić pytanie. Czy szukasz teraz solidnego sposobu na porównanie różnych plików pdf, w tym między innymi artykułów naukowych, czy też szukasz skutecznego, eleganckiego rozwiązania do porównywania artykułów z czasopism, w których wystarczy sprawdzenie, czy tytuł lub DOI są zgodne.
inVader,

Szukam podobnego rozwiązania - teraz używam md5, co jest problematyczne, gdy każde pobieranie zapisuje czas i ip w pliku pdf. Pracuję nad rozwiązaniem z imagemagick ze skryptem opakowującym do przechodzenia między stronami (i być może próbuję pominąć pierwszą stronę na wypadek, gdyby nagłówek został dodany przez czasopismo). Jestem przekonany, że jest to najbardziej niezawodne rozwiązanie . Wiesz, że będzie działać bardzo dobrze, ponieważ jest to ta sama metoda, której używa osoba, porównując wizualnie dwa dokumenty. Jest również całkowicie niezależny od sposobu generowania dokumentu, tylko jego wygląd.
orion

Powiedziałbym również, że porównanie jednej strony jest prawdopodobnie wystarczające - jest mało prawdopodobne, aby dwa dokumenty różniły się, jeśli jedna strona jest taka sama. Notacja blah.pdf[1]wywoła żądaną stronę z dokumentu.
orion

Jeśli naprawdę musisz porównać pliki PDF, w których jeden lub oba są oparte na skanowaniu, myślę, że nie można uniknąć używania OCR. Wiele sugerowanych tutaj podejść tak naprawdę nie rozwiązuje problemu.
gogoud

Odpowiedzi:


4

Ponieważ różni wydawcy używają różnych metod „oznaczania” plików PDF, musisz upewnić się, że porównujesz bez uwzględnienia oznaczeń.

Potrzebujesz także wydajnej metody porównania nowego pliku PDF ze wszystkimi już pobranymi plikami PDF, na wypadek, gdy wielokrotnie pobierasz ten sam plik PDF i jest on np. Oznaczony adresem IP i / lub datownikiem, jak sugerujesz. Nie chcesz używać czasochłonnego mechanizmu porównywania, który porównuje każdy nowy plik PDF z wieloma już pobranymi plikami PDF

Potrzebujesz narzędzia, które usuwa wszystkie możliwe oznaczenia i generuje skrót pozostałych danych. Musisz zachować mapę skrótów → nazwa pliku, która może znajdować się w prostym pliku, a jeśli obliczony skrót znajduje się już w pliku, masz duplikat (i usuń go lub zrób wszystko, co konieczne), a jeśli skrót nie jest jeszcze tam dodajesz skrót i nazwę pliku. Plik wyglądałby mniej więcej tak:

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

Ten plik jest pomijalnie mały w porównaniu do oryginalnych plików PDF. Jeśli masz miliony plików PDF, możesz rozważyć przechowywanie tych danych w bazie danych. Ze względu na wydajność możesz w nim podać rozmiar pliku i liczbę stron ( pdfinfo | egrep -E '^Pages:' | grep -Eo '[0-9]*').


Powyższe popycha problem do usunięcia oznaczeń i wygenerowania skrótu. Jeśli wiesz, skąd pochodzi plik PDF podczas wywoływania procedury generowania skrótu (tj. Jeśli robisz pobieranie programowo), możesz dostosować generowanie skrótu na tej podstawie. Ale nawet bez tego istnieje kilka możliwości generowania skrótów:

  1. jeśli metadane tytułu i autora nie są puste i nie zawierają nieokreślonych ciągów, takich jak „Acrobat” lub „PDF”, można wygenerować skrót na podstawie informacji o autorze i tytule. Użyj, pdfinfo -E file.pdf | grep -E '^(Author:)|(Title:) | md5sumaby uzyskać skrót. Możesz również uwzględnić liczbę stron przy obliczaniu wartości skrótu (' Pages:' w danych pdfinfowyjściowych).
  2. jeśli poprzednia reguła nie działa, a plik PDF zawiera obrazy, wyodrębnij obrazy i wygeneruj skrót dla połączonych danych obrazu. Jeśli obrazy zawierają tekst w stopce lub nagłówku, na przykład „Licencjonowane dla użytkownika Joe”, przed obliczeniem wartości skrótu usuń X linii z góry lub z dołu. Jeśli te oznaczenia znajdują się na dużym szarym tle z literami, to oczywiście nie zadziała, chyba że odfiltrujesz piksele, które nie są całkowicie czarne (do tego możesz użyć imagemagick). Możesz użyć pdfimagesdo wyodrębnienia informacji o obrazie do pliku tymczasowego.
  3. jeśli poprzednie reguły nie działają (ponieważ nie ma obrazów), możesz użyć pdftextdo wyodrębnienia tekstu, odfiltrowania oznaczenia (jeśli odfiltrujesz trochę za dużo, to nie jest problem), a następnie wygenerujesz skrót na podstawie że.

Dodatkowo możesz porównać, czy rozmiar starego pliku znalezionego za pomocą skrótu i ​​sprawdzić, czy mieści się w określonych granicach nowego pliku. Kompresja i iffereferencje w ciągach znaków (IP / data-znacznik czasu) powinny skutkować różnicą mniejszą niż jeden procent.

Jeśli znasz metodę, którą wydawca stosuje przy określaniu wartości skrótu, możesz bezpośrednio zastosować „właściwą” powyższą metodę, ale nawet bez niej możesz sprawdzić metadane i zastosować heurystykę lub określić liczbę obrazów w pliku i porównaj to z liczbą stron (jeśli są blisko, prawdopodobnie masz dokument zawierający skany). pdftextna zeskanowanym obrazie pliki PDF mają także rozpoznawalny wynik.


Jako podstawę do pracy stworzyłem pakiet Pythona, który jest na bitbucket i / lub może być zainstalowany z PyPI przy użyciu pip install ruamel.pdfdouble. Zapewnia to pdfdblpolecenie, które wykonuje skanowanie zgodnie z powyższym opisem w przypadku metadanych, wyodrębnionych obrazów lub tekstu. Nie wykonuje jeszcze żadnego filtrowania oznaczeń (jeszcze) , ale readme opisuje, które (dwie) metody ulepszenia, aby to dodać.

Dołączony plik Readme:

ruamel.pdfdouble

ten pakiet zawiera pdfdblpolecenie:

pdfdbl scan dir1 dir2

Spowoduje to przejście do katalogów podanych jako argument, a dla znalezionych plików PDF utwórz skrót na podstawie (w kolejności):

  • metadane, jeśli są unikalne
  • obrazy, jeśli liczba obrazów
  • tekst

Zakłada się, że pdfinfo, pdfimages i pdftotext` z pakietu poppler-utils są dostępne.

Tworzona jest „baza danych”, na ~/.config/pdfdbl/pdf.lstpodstawie której testowane są kolejne skany.

Usuwanie oznaczeń

W ruamel/pdfdouble/pdfdouble.pyistnieją dwie metody, które mogą być ulepszone, aby odfiltrować znaki w formacie PDF, które czynią je mniej wyjątkowy i uczynić praktycznie te same pliki mają różne skrótów.

W przypadku tekstu PdfData.filter_for_markingnależy rozszerzyć metodę, aby usunąć i oznaczenia z łańcucha będącego jej argumentami i zwrócić wynik.

W przypadku skanowanych obrazów należy ulepszyć tę metodę PdfData.process_image_and_update, np. Odcinając dolne i górne linie X obrazów oraz usuwając szary tekst tła, ustawiając wszystkie czarne piksele na białe. Ta funkcja musi zaktualizować skrót przekazany przy użyciu .update()metody przekazującej przefiltrowane dane.

Ograniczenia

Obecna „baza danych” nie obsługuje ścieżek zawierających znaki nowej linii

To narzędzie jest obecnie tylko Python 2.7.


Ciągi znaków zgodne z IP można zastąpić remodułem Pythona :

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'

W przeszłości korzystałem z pakietu python również pdfrwdo wyodrębniania metadanych, ale nie jest to w stanie obsłużyć zakodowanych plików pdf pdfinfo.
Anthon

2

Dałbym pdftotextkolejną szansę, przynajmniej dla plików PDF w Twojej kolekcji, które faktycznie zawierają tekst (w przeciwnym razie będziesz musiał uruchomić OCR), używając lepszego narzędzia do przetwarzania danych wyjściowych.

Po uzyskaniu (brudnego) wyniku tekstowego uruchom go przez program zaprojektowany do określania podobieństw (zamiast diffróżnic między wierszami, co byłoby szybką ścieżką do szaleństwa).

Rozważmy coś takiego jak String :: podobieństwo perla lub program simhash (który jest dostępny w Debianie, ale nie w Fedorze / RHEL).


2

Pliki PDF zawierają metadane i właśnie sprawdziłem kilka artykułów związanych z fizyką od różnych wydawców i wszystkie mają przynajmniej atrybut „Tytuł”. Dla niektórych tytuł jest rzeczywistym tytułem publikacji, dla niektórych zawiera DOI lub podobne identyfikatory. W każdym razie każdy sprawdzony przeze mnie artykuł zawiera tytuł i zawsze jest czymś unikalnym dla danej publikacji.

Możesz użyć, pdftkaby uzyskać dostęp do metadanych plików PDF i porównać je. Dla twojego celu powinno to zdecydowanie wystarczyć i jest znacznie szybsze niż w pdftotextprzypadku problemów z wydajnością. W przypadku, gdy artykuł naprawdę nie powinien mieć metadanych tytułu, do którego nadal możesz wrócić pdftotext.

Aby zrzucić wszystkie metadane do pliku tekstowego (lub standardowego) w celu dalszego przetwarzania, użyj

pdftk <PDF> dump_data output <TEXTFILE>

lub zapoznaj się z instrukcją, aby uzyskać dodatkowe opcje.

Jeśli chcesz wypróbować ImageMagick , compareale wiele stron powoduje problem, możesz również użyć pdftkdo wyodrębnienia pojedynczych stron i porównania ich wszystkich osobno (może jednak wystarczy porównanie jednej strony).

Oto fragment kodu, który wykorzystuje to podejście do tworzenia diffpodobnego wyjścia PDF dla wielostronicowych plików PDF: https://gist.github.com/mpg/3894692


1

Czy przejrzałeś narzędzie do porównywania treści PDF ? Istnieją opcje wiersza poleceń, które powinny umożliwić zautomatyzowanie procesu.

Możesz uruchomić logikę w dzienniku różnic, który tworzy, aby zobaczyć, jak są one podobne.

W przeciwnym razie możesz spróbować tymczasowo podzielić pliki PDF na wiele plików i porównać je w ten sposób. Prawdopodobnie nadal będziesz mieć duplikaty w ten sposób. Jeden plik PDF może zawierać dodatkową pustą stronę lub coś, co sprawi, że wszystkie kolejne strony będą porównywane jako zupełnie inne.


Mogą to być dwie najdroższe wersje tego zamkniętego programu źródłowego. Wolałbym rozwiązanie typu open source, chociaż nie musi być za darmo.
Jonas Stein,

1

Po skromnym udziale w dyskusji (częściowa odpowiedź):

Po przekonwertowaniu na tekst użyłbym następującego do obliczenia podobieństwa pliku (na podstawie różnicy słów):

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

(1) daje wynik podobny do

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


1

Mam skrypt, który przegląda pdf i najpierw próbuje wyodrębnić tekst pdftotext, ale jeśli to się nie powiedzie (tak jak w przypadku zeskanowanego dokumentu), używa ghostscript do zamiany wielostronicowego zeskanowanego pliku pdf na serię plików png, a następnie używa tesseract do przekształcenia tej serii w pojedynczy plik tekstowy. Jeśli skan ma wystarczającą jakość, robi całkiem dobrą robotę. Łatwo byłoby dodać kod porównujący tekst między plikami, ale nie miałem tego wymagania.

ghostscript i tesseract są zarówno open source, jak i działają z poziomu wiersza poleceń.


Możesz bezpośrednio wyodrębnić zeskanowane obrazy przy użyciu pdfimagespakietu poppler bez dodatkowej utraty jakości, którą można uzyskać dzięki renderowaniu za pomocą ghostscript (co negatywnie wpływa na dowolny OCR, który chcesz zrobić).
Anthon

@Anthon dziękuje za zwrócenie na to uwagi, ale na pewno pdfimagesrobi to samo co ghostscript ( gs), tzn. Wypakowuje obrazy z pdf do jpg / png. Dlaczego jest w tym lepszy niż gs?
gogoud

Renderowanie, które wykonuje ghostscript, zniekształca piksele obrazów, chyba że wszystkie skany mają tę samą rozdzielczość (nie w przypadku np. Odrzucenia krawędzi białych znaków) i tylko wtedy, gdy renderujesz w dokładnie takiej samej rozdzielczości, z jakiej korzystają obrazy
Anthon

@Anthon Ciekawe, zrobiłem trochę testów. Wyniki są bardzo podobne, ale wydaje się, że gs/ tesseract(format pośredni png) działa nieco lepiej niż pdfimages/ tesseract(format pośredni pbm). pdfimagesjest jednak szybszy.
gogoud

0

Jako rozwiązanie zaoferowałbym perla. Istnieje moduł o nazwie, CAM::PDFktóry pozwala wyodrębnić ... treść PDF.

Działa trochę tak:

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

Możesz wyodrębnić tekst i porównać go.

W przypadku tylko zeskanowanych dokumentów - jest to znacznie trudniejsze, ale zakładając, że używają tych samych obrazów podstawowych (np. Nie skanowały ich osobno), prawdopodobnie możesz użyć:

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

Nie przetestowałem tego szczególnie dobrze, ponieważ nie mam twoich dokumentów źródłowych. Myślę, że to podejście powinno załatwić sprawę - nie porównujesz rzeczywistej zawartości obrazu, ponieważ ... cóż, to naprawdę trudne. Ale powinieneś być w stanie rozpoznać podobne obrazy z metadanych.

W przypadku identycznych plików PDF z różnymi metadanymi, wystarczy coś prostego, np. Mieszanie zawartości tekstu i metadanych obrazu.


-1

Istnieje aplikacja Linux, zwana recoll . Może wykonać to zadanie, ale tylko w przypadku plików pdf z warstwą tekstową.


2
recollWydaje mi się, że to wyszukiwarka na komputery. Nie widziałem, jak go użyć, aby znaleźć duplikaty.
Jonas Stein,

1
recollużywa pdftotextdo obsługi plików PDF, czego OP stara się tutaj unikać.
John WH Smith,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.