2012-09-10 10 views
8

Por el momento estoy buscando hacer una fusión de PDF con pyPdf, pero a veces las entradas no están en el orden correcto, entonces estoy buscando raspando cada página para su número de página a determinar el orden en que debe ir (por ejemplo, si alguien divide un libro en 20 PDF de 10 páginas y quiero volver a armarlos).Recuperar números de página del documento con pyPDF

Tengo dos preguntas: 1.) Sé que a veces el número de página se almacena en los datos del documento en alguna parte, ya que he visto archivos PDF que se procesan en Adobe como algo similar a [1243] (10 de 150), pero He leído documentos de este tipo en pyPDF y no puedo encontrar ninguna información que indique el número de página: ¿dónde está almacenado?

2.) Si la avenida n. ° 1 no está disponible, creo que podría recorrer los objetos en una página determinada para tratar de encontrar un número de página: es probable que sea un objeto que tenga un solo número. . Sin embargo, parece que no puedo encontrar una forma clara de determinar el contenido de los objetos. Si me quedo:

pdf.getPage(0).getContents() 

Esto por lo general o bien vuelve:

{'/Filter': '/FlateDecode'} 

o se devuelve una lista de IndirectObject (num, num) objetos. Realmente no sé qué hacer con ninguno de estos y no hay documentación real en él hasta donde yo sé. ¿Alguien está familiarizado con este tipo de cosas que podrían apuntarme en la dirección correcta?

Respuesta

6

Para obtener la documentación completa, consulte la página de 978 de Adobe PDF Reference. :-)

Más específicamente, el archivo PDF contiene metadatos que indican cómo las páginas físicas del PDF se asignan a números de página lógicos y cómo deben formatearse los números de página. Aquí es donde debes buscar resultados canónicos. El ejemplo 2 of this page muestra cómo se ve en el marcado PDF. Tendrás que pescarlo, analizarlo y realizar un mapeo tú mismo.

En PyPDF, para llegar a esta información, tratar, como punto de partida:

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

Por cierto, cuando vea una instancia IndirectObject, puede llamar a su método getObject() para recuperar siendo el objeto real apuntado a.

Su alternativa es, como usted dice, verificar los objetos de texto e intentar averiguar cuál es el número de página. Puede usar extractText() del objeto de la página para esto, pero obtendrá una cadena de regreso y tendrá que intentar pescar el número de página de eso. (Y, por supuesto, el número de página puede ser romano o alfabético en lugar de numérico, y algunas páginas pueden no estar numeradas.) En su lugar, eche un vistazo a cómo extractText() hace su trabajo, PyPDF está escrito en Python, después de todo, y úselo como una base de una rutina que verifica cada objeto de texto en la página individualmente para ver si es como un número de página. Tenga cuidado con TOC/páginas de índice que tienen muchos números de página en ellas.

+0

He intentado leer, pero no sirve .......... ¿Puede dar una muestra de código de trabajo? – dreamer

15

A continuación trabajó para mí:

from PyPDF2 import PdfFileReader 
pdf = PdfFileReader(open('path/to/file.pdf','rb')) 
pdf.getNumPages() 
+1

Tuve que cambiar 'pypdf' por' pyPdf' y el tipo de lectura por 'rb'. –

+7

También noté que esto realmente no responde la pregunta que estaba haciendo, pero resultó ser lo que estaba buscando. (El número de páginas en un pdf) –

+4

Recuerde utilizar la instrucción with para evitar fugas de memoria .... con open ('ruta/a/archivo.pdf', 'rb') como pdf: PdfFileReader (pdf) .getNumPages() – Taran

2

La respuesta por Kindall es muy bueno. Sin embargo, dado que una muestra de código de trabajo fue solicitada más tarde (por soñador) y dado que tenía el mismo problema hoy, me gustaría agregar algunas notas.

  1. estructura en pdf no es uniforme; hay pocas cosas en las que puede confiar, por lo tanto, es muy poco probable que una muestra de código de trabajo funcione para todos.Una muy buena explicación se puede encontrar in this answer.

  2. Según lo explica kindall, lo más probable es que necesite explorar qué pdf está tratando.

así:

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. Como se puede ver en el PDF 1.7 especificación ISO (sección correspondiente here) hay un montón de posibilidades de cómo etiquetar páginas. Como un simple ejemplo de trabajo considerar este script que va a al menos trato con decimales (árabe) y con números romanos:

Guión:

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) 
1

Las otras respuestas utilizan PyPDF/PyPDF2 que parece leer el archivo completo. Esto lleva mucho tiempo para archivos grandes.

Mientras tanto escribí algo rápido y sucio que no tarda tanto en ejecutarse. Hace una llamada de shell pero no estaba al tanto de ninguna otra forma de hacerlo. Puede obtener el número de páginas para pdfs que son ~ 5000 páginas muy rápidamente.

Funciona simplemente llamando al comando de shell "pdfinfo", por lo que probablemente solo funcione en Linux. Solo lo he probado en ubuntu hasta el momento.

Un comportamiento extraño que he visto es que al rodear esto en un bloque try/except no se detectan errores, hay que exceptuar el subproceso.CalledProcessError.

from subprocess import check_output 
def get_num_pages(pdf_path): 
    output = check_output(["pdfinfo", pdf_path]).decode() 
    pages_line = [line for line in output.splitlines() if "Pages:" in line][0] 
    num_pages = int(pages_line.split(":")[1]) 
    return num_pages 
+0

Me acabo de dar cuenta de que la pregunta era específicamente para pypdf, pero este es el primer resultado cuando se busca el número de páginas en un pdf usando Python, por lo que esta respuesta será relevante para la mayoría. –

Cuestiones relacionadas