Знайдіть дублікати PDF-файлів за змістом


9

Деякі журнали генерують різний PDF для кожного завантаження. Наприклад, APS зберігає час та IP-адресу у PDF.

Або є паперова версія з гіперпосиланнями та версія з текстовими посиланнями.

Як можна знайти копію паперів із 90% рівним вмістом у системі Linux за допомогою програмного забезпечення з відкритим кодом?

Я думав про перетворення PDF-файлів у звичайний текст у тимчасовому каталозі pdf2txt. Тоді я міг би відфільтрувати всі назви файлів, які diff a bдають більше x рядків. Але це зовсім не елегантно і не вдасться сканувати публікації. Часописи не надають текст OCR для старих публікацій.

Я також спробував compareу пакеті ImageMagick, але я не міг обробляти багатосторінкові файли PDF за допомогою цього інструменту.

diffpdf 2.1.1 добре працює в графічному інтерфейсі на двох файлах, але я не міг зрозуміти, як застосувати його до багатьох файлів, і останні версії недоступні під жодною ліцензією з відкритим кодом.


1
Оскільки серед відповідей є дуже різні підходи, можливо, було б краще конкретніше і уточнити питання. Зараз ви шукаєте надійний спосіб порівняння різних файлів PDF, включаючи наукові статті серед інших, чи ви намагаєтесь знайти ефективне, елегантне рішення для порівняння статей журналу, де достатньо лише перевірити, чи збігаються заголовок чи DOI.
inVader

Я шукаю аналогічне рішення - зараз я використовую md5, що проблематично, коли кожне завантаження записує час та ip у pdf. Я працюю над рішенням з imagemagick зі скриптом обгортки, щоб прокручувати сторінки (і, можливо, намагаюся пропустити першу сторінку, якщо це заголовок, доданий у журналі). Я дуже впевнений, що це найбільш надійне рішення . Ви знаєте, що це буде добре працювати, оскільки це той самий метод, який людина використовує при візуальному порівнянні двох документів. Він також повністю незалежний від способу генерування документа, лише від його візуального вигляду.
Оріон

Я б також сказав, що порівняння однієї сторінки, ймовірно, достатньо - навряд чи два документи різні, якщо одна сторінка однакова. Позначення blah.pdf[1]викликає потрібну сторінку з документа.
Оріон

Якщо вам дійсно потрібно порівняти pdfs, де один або обидва базуються на скануванні, я думаю, ви не можете уникнути використання OCR. Багато запропонованих тут підходів не реально вирішують проблему.
gogoud

Відповіді:


4

Оскільки різні видавці використовують різні способи "маркування" PDF-файлів, вам потрібно переконатися в порівнянні, не враховуючи маркування.

Вам також потрібен ефективний метод порівняння нового PDF-файлу з усіма вже завантаженими PDF-файлами, якщо ви неодноразово завантажуєте той самий PDF-файл, і він, наприклад, позначений IP-адресою та / або печаткою дати та часу, як ви пропонуєте. Ви не хочете використовувати трудомісткий механізм порівняння, який порівнює кожен новий PDF з багатьма вже завантаженими PDF-файлами

Вам потрібна утиліта, яка знімає кожну з можливих позначок і генерує хеш решти даних. Вам потрібно буде зберегти хеш → карту імен файлів, яка може бути у простому файлі, і якщо обчислюваний хеш уже є у файлі, у вас є дублікат (і видаліть його або зробіть все необхідне), і якщо хеш ще не є там ви додаєте хеш і ім’я файлу. Файл виглядатиме приблизно так:

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

Цей файл недбало малий порівняно з оригінальними PDF-файлами. Якщо у вас є мільйони PDF-файлів, ви можете розглянути можливість зберігання цих даних у базі даних. З метою ефективності ви можете включити розмір файлів і кількість сторінок там ( pdfinfo | egrep -E '^Pages:' | grep -Eo '[0-9]*').


Вищезазначене підштовхує проблему до видалення маркування та генерування хешу. Якщо ви знаєте, звідки походить PDF-файл, коли викликуєте процедуру генерації хешу (тобто, якщо ви завантажуєте програмно), ви можете точно налаштувати геш-генерування на основі цього. Але навіть без цього існує кілька можливостей для створення хешу:

  1. якщо метадані для заголовка та автора не порожні і не містять неспецифічних рядків, таких як "Acrobat" або "PDF", ви можете генерувати хеш на основі лише інформації про автора та заголовка. Використовуйте pdfinfo -E file.pdf | grep -E '^(Author:)|(Title:) | md5sumдля отримання хешу. Ви можете також включити кількість сторінок при обчисленні хеша (' Pages:' у pdfinfoвисновку).
  2. якщо попереднє правило не працює, а PDF містить зображення, витягніть зображення та створіть хеш на комбінованих даних зображення. Якщо зображення коли-небудь містять текст у нижньому колонтитулі чи заголовку, наприклад "Ліцензований користувач Джо", перед обчисленням хеша зніміть X число рядків у верхній або нижній частині. Якщо ця позначка є у великому помаранчевому кольоровому тексті, це звичайно не буде працювати, якщо ви не відфільтруєте пікселі, які не є абсолютно чорними (для цього ви могли б скористатися imagemagick). Ви можете pdfimagesвитягти інформацію про зображення у тимчасовий файл.
  3. якщо попередні правила не працюють (оскільки немає зображень), ви можете використовувати pdftextдля вилучення тексту, відфільтрувати маркування (якщо ви відфільтруєте трохи на багато, це не проблема), а потім генерувати хеш на основі що.

Крім того, ви можете порівняти, чи розмір старого файлу знайдений через хеш, і побачити, чи знаходиться в певних полях з новим файлом. Стиснення та різниці в рядках (IP / дата-час-штамп) повинні спричинити лише менший відсоток різниці.

Якщо ви знаєте метод, який видавець використовує при визначенні хеша, ви можете безпосередньо застосувати «правильний» метод вищезазначеного, але навіть без цього ви можете перевірити метадані та застосувати певну евристику або визначити кількість зображень у файлі і порівняйте це з кількістю сторінок (якщо вони близькі, напевно, у вас є документ, що складається з сканів). pdftextдля сканованих зображень PDF-файли також мають впізнаваний вихід.


В якості основи для роботи я створив пакет python, який знаходиться в бітбукеті та / або може бути встановлений з PyPI за допомогою pip install ruamel.pdfdouble. Це дає вам pdfdblкоманду, яка виконує сканування, як описано вище, на метаданих, витягнутих зображеннях або тексті. Він не здійснює фільтрації маркування (поки що) , але readme описує, які (два) способи покращення робити, додають це.

Readme:

ruamel.pdfdouble

цей пакет забезпечує pdfdblкоманду:

pdfdbl scan dir1 dir2

Це дозволить знизити каталоги, подані як аргумент, і для знайдених файлів PDF створіть хеш на основі (в порядку):

  • метадані, якщо унікальні
  • зображення, якщо кількість зображень
  • текст

Це передбачає, що pdfinfo, pdfimages та pdftotext` з пакету poppler-utils доступні.

Створюється "база даних", ~/.config/pdfdbl/pdf.lstна яку перевіряються подальші сканування.

Видалення маркування

У ruamel/pdfdouble/pdfdouble.pyЄ два способи , які можуть бути посилені , щоб відфільтрувати маркування в форматі PDF , які роблять їх менш унікальним і зробити практично одні і ті ж файли , щоб мати різні хеші.

Для тексту метод PdfData.filter_for_markingслід розширити, щоб видалити та позначити з рядка, який є його аргументами, та повернути результат.

Для відсканованих зображень метод PdfData.process_image_and_updateслід вдосконалити, наприклад, відрізавши зображення внизу та вгорі X-рядків, а також видалити будь-який сірий фон тексту, встановивши всі чорні пікселі на біле. Ця функція потребує оновлення хешу, переданого у використанні .update()методу передачі у відфільтровані дані.

Обмеження

Поточна "база даних" не може обробляти шляхи, що містять нові рядки

Наразі ця утиліта є лише Python 2.7.


IP-рядки, що відповідають IP, можуть бути замінені reмодулем 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'

Раніше я використовував пакет python pdfrwдля вилучення метаданих, але це не може обробити зашифровані файли PDF, де pdfinfoможна.
Антон

2

Я б дав pdftotextще один шанс, принаймні для PDF-файлів у вашій колекції, які насправді мають текст (інакше вам потрібно буде запустити OCR), використовуючи кращий інструмент для обробки результатів.

Після того, як ви отримаєте (брудне) виведення тексту, запустіть його через програму, розроблену для визначення схожості (а не diffз різницевими різницями, що було б швидким шляхом до божевілля).

Розглянемо щось на кшталт Perl: String :: Схожість або програма simhash (яка доступна в Debian, але не у Fedora / RHEL).


2

PDF-файли містять метадані, і я щойно перевірив ряд статей, пов’язаних з фізикою, від різних видавців, і всі вони мають принаймні атрибут "Title". Для деяких заголовок - це фактична назва видання, для деяких вона містить DOI або подібні ідентифікатори. У будь-якому випадку, кожен документ, який я перевірив, містить заголовок, і це завжди щось унікальне для даної публікації.

Ви можете використовувати pdftkдля доступу до метаданих PDF-файлів та їх порівняння. Для вашої мети це, безумовно, повинно бути достатнім і набагато швидшим, ніж pdftotextякщо продуктивність є проблемою. У випадку, якщо папір дійсно не має метаданих заголовка, ви все ще можете повернутися до pdftotext.

Щоб скинути всі метадані в текстовий файл (або stdout) для подальшої обробки

pdftk <PDF> dump_data output <TEXTFILE>

або зверніться до посібника для подальших варіантів.

Якщо ви хочете спробувати ImageMagick , compareале кілька сторінок спричиняють проблеми, ви також можете використати pdftkдля вилучення одних сторінок і порівняння всіх їх окремо (можливо, достатньо лише порівняння однієї).

Ось фрагмент коду, який використовує такий підхід, щоб створити diffподібний вихід PDF для багатосторінкових PDF-файлів: https://gist.github.com/mpg/3894692


1

Ви заглянули у Порівняльник вмісту PDF ? Існують варіанти командного рядка, які дозволять вам автоматизувати процес.

Ви можете запустити якусь логіку в журналі різниці, який він створює, щоб побачити, наскільки вони схожі.

Якщо цього не вдалося, ви можете спробувати розділити PDF на кілька файлів тимчасово і порівняти їх таким чином. Ти, мабуть, все ще маєш дублікати. Один PDF може просто мати додаткову порожню сторінку або щось таке, що призведе до порівняння всіх наступних сторінок як зовсім інших.


Можливо, дві найдорожчі версії цієї закритої програми можуть зробити свою роботу. Я вважаю за краще рішення з відкритим кодом, хоча це не повинно бути безкоштовно.
Йонас Штейн

1

Після скромного внеску в дискусію (часткова відповідь):

Після перетворення в текст я б використав наступне для обчислення (на основі різниці слів) файлу:

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

(1) дає такий результат

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

У мене є сценарій, який переглядає pdf і спершу намагається витягнути текст, використовуючи pdftotext, але якщо це не вдасться (як це буде зі сканованим документом), він використовує ghostscript, щоб перетворити багатосторінковий сканований PDF у ряд png-файлів, а потім використовує tesseract для перетворення цієї серії в єдиний текстовий файл. Якщо сканування достатньої якості, це робить досить непогану роботу. Було б просто додати код, порівнюючи текст між файлами, але у мене не було цієї вимоги.

ghostscript і tesseract - це відкритий код, і робота з командного рядка.


Ви можете безпосередньо витягувати відскановані зображення за допомогою pdfimagesпрограми Poppler без додаткової втрати якості, яку можна отримати при рендерінгу через ghostscript (що негативно впливає на будь-який OCR, який ви хочете зробити).
Антон

@Anthon дякую, що вказав на це, але, безумовно pdfimages, робимо те саме, що і ghostscript ( gs) тут, тобто витягує зображення з pdf у jpg / png. Чому в цьому краще, ніж gs?
gogoud

Відображення, яке робить ghostscript, спотворює пікселі зображень, якщо всі скани не мають однакову роздільну здатність (не у випадку, наприклад, якщо краї білого простору були відкинуті), і тоді лише якщо ви візуалізуєте точно таку саму роздільну здатність, яку використовують зображення
Anthon

@Anthon Цікаво, я трохи провів тестування. Результати дуже схожі, але, схоже, що gs/ tesseract(png проміжний формат) працює трохи краще, ніж pdfimages/ tesseract(pbm проміжний формат). pdfimagesшвидше, хоча.
gogoud

0

Я б запропонував perl як рішення. Існує модуль під назвою, CAM::PDFякий дозволяє витягувати ... PDF-вміст.

Це працює трохи так:

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

Ви можете витягнути текст і порівняти це.

Для сканованих лише документів - це набагато складніше, але якщо припустити, що вони використовують однакові базові зображення (наприклад, окремо їх не сканували), то, ймовірно, ви можете використовувати:

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

Я не перевіряв його особливо добре, тому що у мене немає ваших вихідних документів. Я думаю, що цей підхід повинен зробити трюк - ви не порівнюєте фактичний вміст зображення, тому що .... ну, це справді важко. Але ви повинні мати можливість розпізнавати подібні зображення з метаданих.

Для однакових PDF-файлів з різними метаданими, то щось просте, як хеширование текстового вмісту та метаданих зображень, повинно зробити свою справу.


-1

Існує програма Linux, яка називається відмотка . Він може виконувати завдання, але лише для pdfs з текстовим шаром.


2
Мені recollздається, настільною пошуковою системою. Я не міг побачити, як це використовувати для пошуку дублікатів.
Йонас Штейн

1
recollвикористовує pdftotextдля обробки PDF-файлів, чого ОП намагається тут уникати.
Джон У. Сміт
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.