Temukan file PDF duplikat berdasarkan konten

9

Beberapa jurnal menghasilkan PDF yang berbeda untuk setiap unduhan. APS misalnya menyimpan waktu dan alamat IP dalam PDF.

Atau ada versi kertas dengan tautan hyper dan satu dengan referensi teks.

Bagaimana mungkin menemukan unduhan duplikat kertas dengan 90% konten yang sama pada sistem linux dengan menggunakan perangkat lunak sumber terbuka?

Saya telah berpikir tentang mengkonversi file PDF ke teks biasa di direktori sementara dengan pdf2txt. Lalu saya bisa memfilter semua nama file yang diff a bmenghasilkan lebih dari x baris. Tapi ini tidak elegan sama sekali dan akan gagal dengan publikasi yang dipindai. Jurnal sering tidak menyediakan teks OCR untuk publikasi lama.

Saya juga mencoba comparedi ImageMagick suite, tetapi saya tidak bisa menangani file PDF multi-halaman dengan alat ini.

diffpdf 2.1.1 melakukan pekerjaan yang baik dalam GUI pada dua file, tapi saya tidak tahu cara menerapkannya pada banyak file, dan versi terbaru tidak tersedia di bawah lisensi open source apa pun.

Jonas Stein
sumber
1
Karena ada pendekatan yang sangat berbeda di antara jawaban, mungkin lebih baik untuk lebih spesifik dan mengklarifikasi pertanyaan. Apakah Anda sekarang mencari cara yang kuat untuk membandingkan file pdf yang berbeda termasuk karya ilmiah antara lain atau Anda mencoba untuk menemukan solusi yang efisien dan elegan untuk membandingkan artikel jurnal, di mana hanya memeriksa apakah judul atau DOI yang cocok benar-benar cukup.
inVader
Saya mencari solusi yang sama - sekarang saya menggunakan md5 yang bermasalah ketika setiap unduhan mencatat waktu dan ip di pdf. Saya sedang mengerjakan solusi dengan imagemagick dengan skrip pembungkus untuk mengulang halaman (dan mungkin mencoba untuk melewati halaman pertama jika itu header yang ditambahkan oleh jurnal). Saya sangat yakin bahwa ini adalah solusi yang paling kuat . Anda tahu itu akan bekerja dengan sangat baik karena metode yang sama digunakan seseorang ketika membandingkan dua dokumen secara visual. Itu juga sepenuhnya independen dalam cara dokumen dihasilkan, hanya penampilan visualnya.
orion
Saya juga mengatakan bahwa membandingkan satu halaman mungkin cukup - tidak mungkin dua dokumen berbeda jika satu halaman sama. Notasi blah.pdf[1]akan memanggil halaman yang diinginkan dari dokumen.
orion
Jika Anda benar-benar perlu membandingkan pdf di mana satu atau keduanya didasarkan pada pemindaian saya pikir Anda tidak dapat menghindari menggunakan OCR. Oleh karena itu, banyak pendekatan yang disarankan di sini tidak benar-benar menyelesaikan masalah.
gogoud

Jawaban:

4

Karena penerbit yang berbeda menggunakan metode berbeda "menandai" PDF, Anda perlu memastikan Anda membandingkan tanpa memperhitungkan tanda.

Anda juga memerlukan metode yang efisien untuk membandingkan PDF baru dengan semua PDF yang sudah diunduh seandainya Anda berulang kali mengunduh PDF yang sama dan ditandai misalnya dengan IP dan / atau cap waktu-tanggal seperti yang Anda sarankan. Anda tidak ingin menggunakan mekanisme perbandingan yang memakan waktu yang membandingkan setiap PDF baru dengan banyak PDF yang sudah diunduh

Yang Anda butuhkan adalah utilitas yang menghapus setiap tanda yang mungkin dan menghasilkan hash dari data yang tersisa. Anda harus menyimpan hash → nama file peta, yang dapat berupa file sederhana, dan jika hash yang dihitung sudah ada dalam file Anda memiliki duplikat (dan menghapusnya atau melakukan apa pun yang diperlukan) dan jika hash belum di sana, Anda menambahkan hash dan nama file. File akan terlihat seperti:

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

File itu sangat kecil dibandingkan dengan PDF asli. Jika Anda memiliki jutaan PDF, Anda mungkin mempertimbangkan untuk menyimpan data ini dalam database. Demi efisiensi Anda mungkin ingin memasukkan filesize dan jumlah halaman di sana ( pdfinfo | egrep -E '^Pages:' | grep -Eo '[0-9]*').


Di atas mendorong masalah untuk menghapus tanda dan menghasilkan hash. Jika Anda tahu dari mana PDF berasal ketika menjalankan rutin pembuatan hash (yaitu jika Anda melakukan unduhan secara terprogram), Anda dapat menyempurnakan generasi hash berdasarkan itu. Tetapi bahkan tanpa itu ada beberapa kemungkinan untuk generasi hash:

  1. jika metadata untuk judul dan penulis tidak kosong dan tidak termasuk string non-spesifik seperti "Acrobat" atau "PDF" Anda bisa membuat hash berdasarkan hanya pada informasi penulis dan judul. Gunakan pdfinfo -E file.pdf | grep -E '^(Author:)|(Title:) | md5sumuntuk mendapatkan hash. Anda dapat memasukkan jumlah halaman dalam menghitung hash juga (' Pages:' dalam pdfinfooutput).
  2. jika aturan sebelumnya tidak berfungsi dan PDF berisi gambar, ekstrak gambar dan hasilkan hash pada data gambar gabungan. Jika gambar pernah berisi teks dalam footer atau header seperti "Berlisensi untuk Pengguna Joe", lepaskan sejumlah X garis dari atas atau bawah, sebelum menghitung hash. Jika tanda-tanda itu dalam beberapa teks latar belakang abu-abu berhuruf besar ini tentu saja tidak akan berfungsi, kecuali jika Anda memfilter piksel yang tidak sepenuhnya hitam (untuk itu Anda dapat menggunakan imagemagick). Anda dapat menggunakan pdfimagesuntuk mengekstrak informasi gambar ke dalam file sementara.
  3. jika aturan sebelumnya tidak berfungsi (karena tidak ada gambar), Anda dapat menggunakan pdftextuntuk mengekstrak teks, memfilter penandaan (jika Anda menyaring sedikit ke banyak, itu bukan masalah) dan kemudian menghasilkan hash berdasarkan bahwa.

Selain itu Anda dapat membandingkan apakah ukuran file dari file lama ditemukan melalui hash dan melihat apakah berada dalam margin tertentu dengan file baru. Kompresi dan ifferensi dalam string (IP / date-time-stamp) hanya menghasilkan perbedaan kurang dari satu persen.

Jika Anda mengetahui metode yang digunakan penerbit saat menentukan hash, Anda dapat langsung menerapkan metode "benar" di atas, tetapi bahkan tanpa itu Anda dapat memeriksa metadata dan menerapkan beberapa heuristik, atau menentukan jumlah gambar dalam file dan bandingkan dengan jumlah halaman (jika mereka dekat Anda mungkin memiliki dokumen yang terdiri dari pemindaian). pdftextpada gambar yang dipindai, PDF juga memiliki keluaran yang dapat dikenali.


Sebagai dasar untuk bekerja dari saya membuat paket python yang ada di bitbucket dan / atau dapat diinstal dari PyPI menggunakan pip install ruamel.pdfdouble. Ini memberi Anda pdfdblperintah yang melakukan pemindaian seperti yang dijelaskan di atas pada metadata, gambar yang diekstraksi atau pada teks. Itu tidak melakukan penyaringan tanda (belum) , tetapi readme menggambarkan metode (dua) mana yang harus ditingkatkan untuk menambahkan itu.

Readme yang disertakan:

ruamel.pdfdouble

paket ini menyediakan pdfdblperintah:

pdfdbl scan dir1 dir2

Ini akan berjalan di direktori yang disediakan sebagai argumen dan untuk file PDF yang ditemukan, buat hash berdasarkan (dalam urutan):

  • metadata jika unik
  • gambar jika jumlah gambar
  • teks

Ini mengasumsikan bahwa pdfinfo, pdfimages dan pdftotext` dari paket poppler-utils tersedia.

"Basis data" dibangun untuk ~/.config/pdfdbl/pdf.lstmenguji pemindaian lebih lanjut.

Menghapus tanda

Di ruamel/pdfdouble/pdfdouble.pyada dua metode yang dapat ditingkatkan untuk menyaring tanda di PDF yang membuat mereka kurang unik dan membuat hampir file yang sama untuk memiliki hash yang berbeda.

Untuk teks metode PdfData.filter_for_markingharus diperluas untuk menghapus dan menandai dari string yang merupakan argumennya dan mengembalikan hasilnya.

Untuk gambar yang dipindai metode PdfData.process_image_and_updateperlu ditingkatkan, misalnya dengan memotong gambar bagian bawah dan garis X atas, dan dengan menghapus teks latar abu-abu dengan mengatur semua piksel hitam menjadi putih. Fungsi ini perlu memperbarui hash yang diteruskan menggunakan .update()metode meneruskan data yang difilter.

Batasan

"Database" saat ini tidak dapat menangani jalur yang berisi baris baru

Utilitas ini saat ini hanya Python 2.7.


Stringparts yang sesuai dengan IP dapat diganti dengan remodul 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
sumber
Di masa lalu saya telah menggunakan paket python pdfrwuntuk mengekstraksi metadata juga, tetapi itu tidak dapat menangani file pdf terenkripsi, di mana pdfinfobisa.
Anthon
2

Saya akan memberikan pdftotextkesempatan lain, setidaknya untuk PDF dalam koleksi Anda yang benar-benar memiliki teks (jika tidak, Anda harus menjalankan OCR), menggunakan alat yang lebih baik untuk memproses output.

Setelah Anda memiliki output teks (kotor), jalankan melalui program yang dirancang untuk menentukan kesamaan (bukan diffperbedaan baris demi baris, yang akan menjadi jalan cepat menuju kegilaan).

Pertimbangkan sesuatu seperti String perl :: Similarity atau program simhash (yang tersedia di Debian tetapi tidak di Fedora / RHEL).

Adam Katz
sumber
2

PDF berisi metadata dan saya baru saja memeriksa sejumlah makalah terkait fisika dari penerbit yang berbeda dan mereka semua setidaknya memiliki atribut "Judul". Bagi sebagian orang, judul tersebut adalah judul publikasi yang sebenarnya, untuk beberapa judul berisi DOI atau pengidentifikasi serupa. Bagaimanapun, setiap makalah yang saya periksa berisi judul, dan selalu merupakan sesuatu yang unik untuk publikasi yang diberikan.

Anda dapat menggunakan pdftkuntuk mengakses metadata dari PDF dan membandingkannya. Untuk tujuan Anda, ini pasti sudah cukup dan jauh lebih cepat daripada pdftotextjika kinerja adalah masalah. Jika kertas benar-benar tidak boleh memiliki judul metadata Anda masih bisa kembali ke pdftotext.

Untuk membuang semua metadata ke file teks (atau stdout) untuk diproses lebih lanjut

pdftk <PDF> dump_data output <TEXTFILE>

atau lihat manual untuk opsi lebih lanjut.

Jika Anda ingin mencoba ImageMagick 's comparetetapi beberapa halaman penyebab masalah, Anda juga bisa menggunakan pdftkuntuk mengekstrak halaman tunggal dan membandingkan semua dari mereka secara terpisah (mungkin hanya membandingkan satu pun cukup, meskipun).

Berikut ini adalah cuplikan kode yang menggunakan pendekatan ini untuk membuat diffoutput PDF seperti-untuk PDF multi-halaman: https://gist.github.com/mpg/3894692

penyerbu
sumber
1

Sudahkah Anda melihat Pembanding Konten PDF ? Ada opsi baris perintah yang seharusnya memungkinkan Anda mengotomatiskan proses.

Anda bisa menjalankan semacam logika pada log perbedaan yang dibuatnya untuk melihat betapa miripnya mereka.

Gagal Anda mencoba memisahkan PDF ke dalam beberapa file sementara dan membandingkannya. Anda mungkin masih memiliki duplikat seperti itu. Satu PDF mungkin hanya memiliki halaman kosong tambahan atau sesuatu yang akan menyebabkan semua halaman berikutnya menjadi sangat berbeda.

Bratchley
sumber
Mungkin dua versi paling mahal dari program sumber tertutup ini dapat melakukan pekerjaan. Saya lebih suka solusi open source, meskipun tidak perlu gratis.
Jonas Stein
1

Berikut kontribusi sederhana untuk diskusi (jawaban parsial):

Setelah dikonversi ke teks saya akan menggunakan yang berikut ini untuk menghitung smilarity file (berdasarkan perbedaan kata):

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

(1) menghasilkan hasil seperti

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

Joao
sumber
1

Saya memiliki skrip yang melihat pdf dan pertama kali mencoba mengekstraksi teks menggunakan pdftotext, tetapi jika ini gagal (karena akan dengan dokumen yang dipindai), ia menggunakan ghostscript untuk mengubah pdf multi-halaman yang dipindai menjadi serangkaian file png dan kemudian menggunakan tesseract untuk mengubah seri ini menjadi satu file teks. Jika pemindaiannya berkualitas memadai, ia melakukan pekerjaan yang cukup bagus. Akan lebih mudah untuk menambahkan kode yang membandingkan teks antara file tetapi saya belum memiliki persyaratan ini.

ghostscript dan tesseract keduanya open source dan bekerja dari baris perintah.

gogoud
sumber
Anda dapat langsung mengekstrak gambar yang dipindai menggunakan pdfimagesdari paket poppler tanpa kehilangan kualitas tambahan yang bisa Anda dapatkan dengan rendering melalui ghostscript (yang secara negatif mempengaruhi OCR yang ingin Anda lakukan).
Anthon
@Anthon terima kasih untuk menunjukkan ini, tapi pasti pdfimageshanya melakukan hal yang sama dengan ghostscript ( gs) di sini yaitu mengekstraksi gambar dari pdf ke jpg / png. Mengapa ini lebih baik daripada ini gs?
gogoud
Render yang ghostscript memang mendistorsi piksel gambar kecuali semua pemindaian memiliki resolusi yang sama (tidak seperti misalnya jika tepi spasi dibuang) dan kemudian hanya jika Anda membuat pada resolusi yang sama persis menggunakan gambar
Anthon
@Anton Menarik, saya telah melakukan sedikit pengujian. Hasilnya sangat mirip tetapi tampaknya gs/ tesseract(format menengah png) bekerja sedikit lebih baik daripada pdfimages/ tesseract(format menengah pbm). pdfimageslebih cepat.
gogoud
0

Saya akan menawarkan perl sebagai solusi. Ada modul bernama CAM::PDFyang memungkinkan Anda mengekstrak ... konten PDF.

Kerjanya sedikit seperti ini:

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

Anda dapat mengekstrak teks dan membandingkannya.

Untuk hanya dokumen yang dipindai - jauh lebih sulit, tetapi dengan asumsi mereka menggunakan gambar dasar yang sama (mis. Belum dipindai secara terpisah) maka Anda mungkin dapat menggunakan:

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

Saya belum mengujinya dengan baik, karena saya tidak memiliki dokumen sumber Anda. Saya pikir pendekatan ini harus melakukan trik - Anda tidak membandingkan konten gambar yang sebenarnya, karena .... yah, itu sangat sulit. Tetapi Anda harus dapat mengenali gambar serupa dari metadata.

Untuk PDF identik dengan metadata berbeda, maka sesuatu yang sederhana seperti hashing konten teks dan metadata gambar harus melakukan trik.

Sobrique
sumber
-1

Ada aplikasi Linux, yang disebut recoll . Itu dapat melakukan tugas, tetapi hanya untuk pdf dengan lapisan teks.

annndrey
sumber
2
Bagi saya recollsepertinya mesin pencari desktop. Saya tidak bisa melihat, bagaimana menggunakannya untuk menemukan duplikat.
Jonas Stein
1
recollgunakan pdftotextuntuk menangani PDF, yang ingin dihindari oleh OP di sini.
John WH Smith