コンテンツによって重複するPDFファイルを見つける


9

一部のジャーナルは、ダウンロードごとに異なるPDFを生成します。たとえば、APSは時間とIPアドレスをPDFに保存します。

または、ハイパーリンク付きの紙バージョンとテキスト参照付きの紙バージョンがあります。

オープンソースソフトウェアを使用して、Linuxシステムでコンテンツが90%等しい論文の重複ダウンロードをどのように見つけることができますか?

一時ディレクトリでPDFファイルをプレーンテキストに変換することを検討していますpdf2txt。次にdiff a b、x行を超える結果となるすべてのファイル名をフィルタリングできます。しかし、これはまったくエレガントではなく、スキャンされた出版物では失敗します。多くの場合、ジャーナルは古い出版物のOCRテキストを提供していません。

compareImageMagickスイートも試してみましたが、このツールでは複数ページのPDFファイルを処理できませんでした。

diffpdf 2.1.1は、2つのファイルのGUIでうまく機能しますが、多くのファイルにそれを適用する方法を理解できませんでした。また、オープンソースライセンスでは最新バージョンを利用できません。


1
回答には非常に異なるアプローチがあるため、より具体的で質問を明確にするとよいでしょう。特に科学論文を含むさまざまなpdfファイルを比較するための強力な方法を探していますか?それとも、ジャーナルの記事を比較するための効率的で洗練されたソリューションを見つけようとしていますか?
inVader 2015年

私は同様の解決策を探しています-今私はmd5を使用していますが、これはすべてのダウンロードがPDFに時間とIPを記録するときに問題があります。ページをループするラッパースクリプトを備えたimagemagickを使用したソリューションに取り組んでいます(ジャーナルによって追加されたヘッダーの場合は、最初のページをスキップしてみてください)。これが可能限り最も堅牢なソリューションであると確信しています。2つのドキュメントを視覚的に比較するときに人が使用するのと同じ方法であるため、非常にうまく機能することがわかっています。また、ドキュメントの生成方法から完全に独立しており、視覚的な外観のみが異なります。
オリオン

また、1つのページの比較で十分だと思います。1つのページが同じ場合、2つのドキュメントが異なることはまずありません。表記blah.pdf[1]は、ドキュメントから目的のページを呼び出します。
オリオン

1つまたは両方がスキャンに基づいているPDFを本当に比較する必要がある場合、OCRの使用は避けられないと思います。したがって、ここで提案されているアプローチの多くは、実際には問題を解決しません。
gogoud 2015年

回答:


4

発行元によってPDFの「マーキング」方法が異なるため、マーキングを考慮せずに比較する必要があります。

また、同じPDFを繰り返しダウンロードする場合に、新しいPDFをすでにダウンロードされているすべてのPDFと比較する効率的な方法も必要です。新しい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に画像が含まれている場合は、画像を抽出し、結合された画像データにハッシュを生成します。画像に「Licensed to Joe User」のようなフッターまたはヘッダーのテキストが含まれている場合は、ハッシュを計算する前に、上部または下部からX行の行を削除します。そのマーキングが大きな文字の灰色の背景テキストにある場合、完全に黒ではないピクセルを除外しない限り(これを使用できるためimagemagick)、これはもちろん機能しません。を使用pdfimagesして、イメージ情報を一時ファイルに抽出できます。
  3. 以前のルールが機能しない場合(画像がないため)pdftext、テキストを抽出し、マーキングをフィルターで除外し(少しだけフィルターで除外しても問題はありません)、次に基づいてハッシュを生成します。それ。

さらに、ハッシュを介して古いファイルのファイルサイズが見つかったかどうかを比較し、新しいファイルと特定のマージン内にあるかどうかを確認できます。文字列の圧縮と差異(IP / date-time-stamp)は、1%未満の差異になるだけです。

パブリッシャーがハッシュを決定するときに使用する方法がわかっている場合は、上記の「正しい」方法を直接適用できますが、それがなくてもメタデータを確認していくつかのヒューリスティックを適用するか、ファイル内の画像の数を決定できますそして、それをページ数と比較します(ページが近い場合は、スキャンで構成されたドキュメントがある可能性があります)。pdftextスキャンした画像のPDFにも認識可能な出力があります。


作業の基礎として、bitbucket上にある、またはを使用してPyPIからインストールできるpythonパッケージを作成しましたpip install ruamel.pdfdouble。これによりpdfdbl、メタデータ、抽出された画像、またはテキストに対して上記のスキャンを実行するコマンドが提供されます。 マーキングのフィルタリングは(まだ)行われていませんが、readmeはそれを追加するために拡張する(2つの)メソッドを説明しています。

含まれているreadme:

ruamel.pdfdouble

このパッケージは次のpdfdblコマンドを提供します:

pdfdbl scan dir1 dir2

これは、引数として提供されたディレクトリをたどり、見つかったPDFファイルに対して、次の順序でハッシュを作成します。

  • 一意の場合はメタデータ
  • 画像数の場合は画像
  • テキスト

これは、poppler-utilsパッケージのpdfinfo、pdfimages、pdftotext`が利用可能であることを前提としています。

「データベース」が構築され~/.config/pdfdbl/pdf.lst、それに対してさらなるスキャンがテストされます。

マーキングを削除する

ではruamel/pdfdouble/pdfdouble.py、彼らが少ないユニークにし、異なるハッシュを持って事実上同じファイルを作成するPDFにマーキングをフィルタリングするために強化することができる2つの方法があります。

テキストの場合、メソッドPdfData.filter_for_markingを拡張して、引数である文字列からマーキングを削除し、結果を返す必要があります。

スキャンした画像の場合PdfData.process_image_and_update、たとえば画像の下部と上部のX線を切り取り、すべての黒のピクセルを白に設定して灰色の背景テキストを削除するなど、方法を強化する必要があります。この関数.update()は、フィルタリングされたデータを渡すメソッドを使用して、渡されたハッシュを更新する必要があります。

制限事項

現在の「データベース」は改行を含むパスを処理できません

このユーティリティは現在Python 2.7のみです。


IP準拠のstringpartsは、Pythonのreモジュールで置き換えることができます。

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'

過去には、pdfrwメタデータの抽出にもpythonパッケージを使用しましたが、暗号化されたpdfファイルは処理できませんpdfinfo
Anthon

2

pdftotext少なくとも、実際にテキストが含まれているコレクション内のPDF(それ以外の場合はOCRを実行する必要があります)には、出力を処理するためのより良いツールを使用して、別の機会を与えます。

(ダーティ)テキスト出力を取得したら、類似性を判断するように設計されたプログラムで実行します(diff行ごとの違いではなく、狂気への素早いパスになるでしょう)。

perlのString :: Similaritysimhashプログラム(Debianで利用可能ですが、Fedora / RHELでは利用できません)のようなものを考えてください。


2

PDFにはメタデータが含まれており、さまざまな出版社からの物理学関連の論文をいくつか確認したところ、それらすべてに少なくとも「タイトル」属性が含まれています。タイトルによっては、出版物の実際のタイトルである場合もあれば、DOIまたは同様の識別子が含まれる場合もあります。とにかく、私がチェックしたすべての論文にはタイトルが含まれており、それは常に特定の出版物に固有のものです。

を使用pdftkしてPDFのメタデータにアクセスし、それらを比較できます。あなたの目的のために、これは間違いなく十分であり、pdftotextパフォーマンスが問題である場合よりもはるかに速いはずです。論文に実際にタイトルメタデータが含まれていない場合でも、フォールバックできますpdftotext

すべてのメタデータをテキストファイル(またはstdout)にダンプして、さらに処理する

pdftk <PDF> dump_data output <TEXTFILE>

または、その他のオプションについては、マニュアルを参照してください。

あなたは試してみたい場合はImageMagickcompare問題原因が、複数のページを、あなたも使用することができますpdftk(多分ちょうど単一のものを比較するのに、十分である)、単一のページを抽出し、個別にそれらのすべてを比較します。

このアプローチを使用して、diffマルチページPDFのようなPDF出力を作成するコードスニペットを次に示します。https//gist.github.com/mpg/3894692


1

PDFコンテンツ比較ツールを調べましたか?プロセスを自動化できるコマンドラインオプションがあります。

作成した差分ログでなんらかのロジックを実行して、それらがどの程度類似しているかを確認できます。

PDFを一時的に複数のファイルに分割して、それらをそのように比較しようとする可能性があることに失敗します。ただし、おそらく同じ方法で重複することになります。1つのPDFに余分な空白ページがあるか、後続のすべてのページが完全に異なるものとして比較される原因となるものがあります。


このクローズドソースプログラムの2つの最も高価なバージョンがその仕事をすることができます。無料である必要はありませんが、オープンソースソリューションをお勧めします。
Jonas Stein

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はどちらもオープンソースであり、コマンドラインから機能します。


pdfimagesghostscriptを介したレンダリングで発生する可能性のある品質をさらに損なうことなく、popplerパッケージからスキャンしたイメージを直接抽出できます(これは、実行するOCRに悪影響を及ぼします)。
Anthon

@Anthonこれを指摘してくれてありがとう、確かにここでpdfimagesghostscript(gs)と同じことを実行しています。つまり、pdfからjpg / pngに画像を抽出しています。なぜこれよりも優れているのですgsか?
gogoud 2015年

すべてのスキャンの解像度が同じでない限り(たとえば、空白のエッジが破棄された場合は除き)、画像が使用するまったく同じ解像度でレンダリングした場合にのみ、ghostscriptが画像のピクセルを歪めるレンダリング
Anthon

@Anthon興味深い。少しテストを行った。結果は非常に似ていますが、gs/ tesseract(png中間形式)はpdfimages/ tesseract(pbm中間形式)よりもわずかに優れているようです。pdfimagesでも速いです。
gogoud 2015年

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

recollと呼ばれるLinuxアプリケーションがあります。タスクを実行できますが、テキストレイヤーのあるPDFに対してのみです。


2
私にrecollはデスクトップ検索エンジンのようです。私はそれを使用して重複を見つける方法を見ることができませんでした。
Jonas Stein 14

1
recollpdftotextここでは、OPが回避しようとしているPDFの処理に使用します。
ジョンWHスミス
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.