27

現時点では、pyPdf を使用して PDF をマージすることを検討していますが、入力が正しい順序でない場合があるため、各ページのページ番号をスクレイピングして、順序を決定することを検討しています (たとえば、誰かが本を 20 個の 10 ページの PDF に分割しましたが、私はそれらを元に戻したいと思っています)。

2 つの質問があります - 1.) Adob​​e で [1243] (10/150) のようにレンダリングされる PDF を見たことがありますが、ページ番号が文書データのどこかに保存されていることがありますが、この種のドキュメントを pyPDF に変換すると、ページ番号を示す情報が見つかりません。これはどこに保存されていますか?

2.) アベニュー #1​​ が利用できない場合は、特定のページのオブジェクトを反復してページ番号を見つけようとすることができると思います。おそらく、単一の番号を持つ独自のオブジェクトである可能性があります。ただし、オブジェクトの内容を特定する明確な方法が見つからないようです。私が実行した場合:

pdf.getPage(0).getContents()

これは通常、次のいずれかを返します。

{'/Filter': '/FlateDecode'}

または IndirectObject(num, num) オブジェクトのリストを返します。これらのいずれかをどうするかは本当にわかりません。私が知る限り、実際のドキュメントはありません。私を正しい方向に向けることができるこの種のことに精通している人はいますか?

4

6 に答える 6

9

完全なドキュメントについては、Adobe の 978 ページのPDF リファレンスを参照してください。:-)

具体的には、PDF ファイルには、PDF の物理ページを論理ページ番号にマップする方法と、ページ番号をフォーマットする方法を示すメタデータが含まれています。これは、正規の結果を得る場所です。このページの例 2は、これが PDF マークアップでどのように見えるかを示しています。それを釣り上げて解析し、自分でマッピングを実行する必要があります。

PyPDF では、この情報を取得するには、出発点として次のことを試してください。

pdf.trailer["/Root"]["/PageLabels"]["/Nums"]

ところで、IndirectObjectインスタンスが表示されたら、そのgetObject()メソッドを呼び出して、指している実際のオブジェクトを取得できます。

あなたが言うように、あなたの代わりに、テキストオブジェクトをチェックして、どれがページ番号であるかを見つけようとすることです. これには page オブジェクトを使用できますextractText()が、1 つの文字列が返されるので、そこからページ番号を取得する必要があります。(そしてもちろん、ページ番号は数字ではなくローマ字またはアルファベットである可能性があり、一部のページには番号が付けられていない可能性があります。) 代わりに、実際にその仕事がどのように行われるかを見てくださいextractText()— 結局、PyPDF は Python で書かれています — そしてそれをページ上の各テキストオブジェクトを個別にチェックして、ページ番号のようなものかどうかを確認するルーチンの基礎。多くのページ番号を含む目次/索引ページには注意してください。

于 2012-09-11T15:36:37.783 に答える
5

kindallの答えはとても良いです。ただし、後で(夢想家から)動作するコード サンプルが要求されたため、今日も同じ問題が発生したため、いくつかのメモを追加したいと思います。

  1. pdf 構造は均一ではありません。信頼できるものはかなり少ないため、実際に動作するコード サンプルがすべての人に動作する可能性はほとんどありません。非常に良い説明がこの回答にあります。

  2. kindall で説明されているように、扱っている pdf を調査する必要がある可能性が最も高いでしょう。

そのようです:

import sys
import PyPDF2 as pyPdf

"""Open your pdf"""
pdf = pyPdf.PdfFileReader(open(sys.argv[1], "rb"))

"""Explore the /PageLabels (if it exists)"""

try:
    page_label_type = pdf.trailer["/Root"]["/PageLabels"]
    print(page_label_type)
except:
    print("No /PageLabel object")

"""Select the item that is most likely to contain the information you desire; e.g.
       {'/Nums': [0, IndirectObject(42, 0)]}
   here, we only have "/Num". """

try:
    page_label_type = pdf.trailer["/Root"]["/PageLabels"]["/Nums"]
    print(page_label_type)
except:
    print("No /PageLabel object")

"""If you see a list, like
       [0, IndirectObject(42, 0)]
   get the correct item from it"""

try:
    page_label_type = pdf.trailer["/Root"]["/PageLabels"]["/Nums"][1]
    print(page_label_type)
except:
    print("No /PageLabel object")

"""If you then have an indirect object, like
       IndirectObject(42, 0)
   use getObject()"""

try:
    page_label_type = pdf.trailer["/Root"]["/PageLabels"]["/Nums"][1].getObject()
    print(page_label_type)
except:
    print("No /PageLabel object")

"""Now we have e.g.
       {'/S': '/r', '/St': 21}
   meaning roman numerals, starting with page 21, i.e. xxi. We can now also obtain the two variables directly."""

try:
    page_label_type = pdf.trailer["/Root"]["/PageLabels"]["/Nums"][1].getObject()["/S"]
    print(page_label_type)
    start_page = pdf.trailer["/Root"]["/PageLabels"]["/Nums"][1].getObject()["/St"]
    print(start_page)
except:
    print("No /PageLabel object")
  1. ISO pdf 1.7 仕様 (関連するセクションはこちら)からわかるように、ページにラベルを付ける方法には多くの可能性があります。簡単な作業例として、少なくとも 10 進数 (アラビア語) とローマ数字を処理する次のスクリプトを考えてみましょう。

脚本:

import sys
import PyPDF2 as pyPdf

def arabic_to_roman(arabic):
    roman = ''
    while arabic >= 1000:
      roman += 'm'
      arabic -= 1000
    diffs = [900, 500, 400, 300, 200, 100, 90, 50, 40, 30, 20, 10, 9, 5, 4, 3, 2, 1]
    digits = ['cm', 'd', 'cd', 'ccc', 'cc', 'c', 'xc', 'l', 'xl', 'xxx', 'xx', 'x', 'ix', 'v', 'iv', 'iii', 'ii', 'i']
    for i in range(len(diffs)):
      if arabic >= diffs[i]:
        roman += digits[i]
        arabic -= diffs[i]
    return(roman)

def get_page_labels(pdf):
    try:
        page_label_type = pdf.trailer["/Root"]["/PageLabels"]["/Nums"][1].getObject()["/S"]
    except:
        page_label_type = "/D"
    try:
        page_start = pdf.trailer["/Root"]["/PageLabels"]["/Nums"][1].getObject()["/St"]
    except:
        page_start = 1
    page_count = pdf.getNumPages()
    ##or, if you feel fancy, do:
    #page_count = pdf.trailer["/Root"]["/Pages"]["/Count"]
    page_stop = page_start + page_count 

    if page_label_type == "/D":
        page_numbers = list(range(page_start, page_stop))
        for i in range(len(page_numbers)):
            page_numbers[i] = str(page_numbers[i])
    elif page_label_type == '/r':
        page_numbers_arabic = range(page_start, page_stop)
        page_numbers = []
        for i in range(len(page_numbers_arabic)):
            page_numbers.append(arabic_to_roman(page_numbers_arabic[i]))

    print(page_label_type)
    print(page_start)
    print(page_count)
    print(page_numbers)

pdf = pyPdf.PdfFileReader(open(sys.argv[1], "rb"))
get_page_labels(pdf)
于 2016-03-01T17:04:03.770 に答える