Fusionar archivos PDF

126

¿Es posible, usando Python, fusionar archivos PDF separados?

Suponiendo que sea así, necesito extender esto un poco más. Espero recorrer las carpetas de un directorio y repetir este procedimiento.

Y puedo estar presionando mi suerte, pero ¿es posible excluir una página que está contenida en los PDF (la generación de mi informe siempre crea una página en blanco adicional)?

Btibert3
fuente

Respuestas:

122

Utilice Pypdf o su sucesor PyPDF2 :

Una biblioteca Pure-Python construida como un kit de herramientas PDF. Es capaz de:
* dividir documentos página por página,
* fusionar documentos página por página,

(y mucho más)

Aquí hay un programa de muestra que funciona con ambas versiones.

#!/usr/bin/env python
import sys
try:
    from PyPDF2 import PdfFileReader, PdfFileWriter
except ImportError:
    from pyPdf import PdfFileReader, PdfFileWriter

def pdf_cat(input_files, output_stream):
    input_streams = []
    try:
        # First open all the files, then produce the output file, and
        # finally close the input files. This is necessary because
        # the data isn't read from the input files until the write
        # operation. Thanks to
        # /programming/6773631/problem-with-closing-python-pypdf-writing-getting-a-valueerror-i-o-operation/6773733#6773733
        for input_file in input_files:
            input_streams.append(open(input_file, 'rb'))
        writer = PdfFileWriter()
        for reader in map(PdfFileReader, input_streams):
            for n in range(reader.getNumPages()):
                writer.addPage(reader.getPage(n))
        writer.write(output_stream)
    finally:
        for f in input_streams:
            f.close()

if __name__ == '__main__':
    if sys.platform == "win32":
        import os, msvcrt
        msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
    pdf_cat(sys.argv[1:], sys.stdout)
Gilles 'SO- deja de ser malvado'
fuente
19
Y ahora, pypi.python.org/pypi/PyPDF2 , que es el proyecto sucesor de PyPDF
David Fraser
Funciona para mí solo con la apertura en modo binario (flujos de entrada y también flujo de salida). open(input_file), 'r+b', y en lugar de sys.stdout utilizo output_stream = open('result.pdf', 'w+b').
Simeon Borko
@SimeonBorko Suelta el +, significa "leer y escribir" y ninguno de los archivos se lee y escribe. Agregué soporte de salida de soporte de Windows basado en stackoverflow.com/questions/2374427/… .
Gilles 'SO- deja de ser malvado'
PyPDF2 / 3 no es estable, ¿cómo puedo fusionar archivos pdf sin PyPDF2 / 3?
GoingMyWay
2
Tuve que usar sys.stdout.bufferPython 3.6.8 (Linux)
Greyshack
197

Puede usar la clase de PyPdf2PdfMerger .

Concatenación de archivos

Simplemente puede concatenar archivos utilizando el appendmétodo.

from PyPDF2 import PdfFileMerger

pdfs = ['file1.pdf', 'file2.pdf', 'file3.pdf', 'file4.pdf']

merger = PdfFileMerger()

for pdf in pdfs:
    merger.append(pdf)

merger.write("result.pdf")
merger.close()

Puede pasar identificadores de archivo en lugar de rutas de archivo si lo desea.

Fusión de archivos

Si desea un control más detallado de la fusión, existe un mergemétodo de PdfMerger, que le permite especificar un punto de inserción en el archivo de salida, lo que significa que puede insertar las páginas en cualquier lugar del archivo. El appendmétodo se puede considerar como un mergepunto en el que el punto de inserción es el final del archivo.

p.ej

merger.merge(2, pdf)

Aquí insertamos el pdf completo en la salida pero en la página 2.

Rangos de páginas

Si desea controlar qué páginas se agregan desde un archivo en particular, puede usar el pagesargumento de palabra clave appendy merge, pasando una tupla en el formulario (start, stop[, step])(como la rangefunción regular ).

p.ej

merger.append(pdf, pages=(0, 3))    # first 3 pages
merger.append(pdf, pages=(0, 6, 2)) # pages 1,3, 5

Si especifica un rango no válido, obtendrá un IndexError.

Nota: también que para evitar que los archivos queden abiertos, se PdfFileMergerdebe llamar al método s close cuando se haya escrito el archivo combinado. Esto asegura que todos los archivos se cierren (entrada y salida) de manera oportuna. Es una pena que PdfFileMergerno se implemente como administrador de contexto, por lo que podemos usar la withpalabra clave, evitar el cierre explícito y obtener una seguridad de excepción fácil.

Es posible que también desee consultar el pdfcatscript proporcionado como parte de pypdf2. Potencialmente, puede evitar la necesidad de escribir código por completo.

El github de PyPdf2 también incluye un código de ejemplo que demuestra la fusión.

Paul Rooney
fuente
14

Combinar todos los archivos pdf que están presentes en un directorio

Ponga los archivos pdf en un directorio. Lanzar el programa. Obtienes un PDF con todos los PDF combinados.

import os
from PyPDF2 import PdfFileMerger

x = [a for a in os.listdir() if a.endswith(".pdf")]

merger = PdfFileMerger()

for pdf in x:
    merger.append(open(pdf, 'rb'))

with open("result.pdf", "wb") as fout:
    merger.write(fout)
Giovanni G. PY
fuente
8

La pdfrwbiblioteca puede hacer esto con bastante facilidad, asumiendo que no necesita conservar marcadores y anotaciones, y que sus archivos PDF no están encriptados. cat.pyes un ejemplo de script de concatenación y subset.pyes un ejemplo de script de subconjunto de páginas.

La parte relevante del script de concatenación: se supone que inputses una lista de nombres de archivos de entrada y outfnes un nombre de archivo de salida:

from pdfrw import PdfReader, PdfWriter

writer = PdfWriter()
for inpfn in inputs:
    writer.addpages(PdfReader(inpfn).pages)
writer.write(outfn)

Como puede ver en esto, sería bastante fácil omitir la última página, por ejemplo, algo como:

    writer.addpages(PdfReader(inpfn).pages[:-1])

Descargo de responsabilidad: soy el pdfrwautor principal .

Patrick Maupin
fuente
1
Este es el más estable.
GoingMyWay
1
Esta biblioteca merece más reputación.
GoingMyWay
6

¿Es posible, usando Python, fusionar archivos PDF separados?

Si.

El siguiente ejemplo combina todos los archivos de una carpeta en un único archivo PDF nuevo:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from argparse import ArgumentParser
from glob import glob
from pyPdf import PdfFileReader, PdfFileWriter
import os

def merge(path, output_filename):
    output = PdfFileWriter()

    for pdffile in glob(path + os.sep + '*.pdf'):
        if pdffile == output_filename:
            continue
        print("Parse '%s'" % pdffile)
        document = PdfFileReader(open(pdffile, 'rb'))
        for i in range(document.getNumPages()):
            output.addPage(document.getPage(i))

    print("Start writing '%s'" % output_filename)
    with open(output_filename, "wb") as f:
        output.write(f)

if __name__ == "__main__":
    parser = ArgumentParser()

    # Add more options if you like
    parser.add_argument("-o", "--output",
                        dest="output_filename",
                        default="merged.pdf",
                        help="write merged PDF to FILE",
                        metavar="FILE")
    parser.add_argument("-p", "--path",
                        dest="path",
                        default=".",
                        help="path of source PDF files")

    args = parser.parse_args()
    merge(args.path, args.output_filename)
Martín Thoma
fuente
3
from PyPDF2 import PdfFileMerger
import webbrowser
import os
dir_path = os.path.dirname(os.path.realpath(__file__))

def list_files(directory, extension):
    return (f for f in os.listdir(directory) if f.endswith('.' + extension))

pdfs = list_files(dir_path, "pdf")

merger = PdfFileMerger()

for pdf in pdfs:
    merger.append(open(pdf, 'rb'))

with open('result.pdf', 'wb') as fout:
    merger.write(fout)

webbrowser.open_new('file://'+ dir_path + '/result.pdf')

Repositorio de Git: https://github.com/mahaguru24/Python_Merge_PDF.git

guruprasad mulay
fuente
2

aquí, http://pieceofpy.com/2009/03/05/concatenating-pdf-with-python/ , ofrece una solución.

similar:

from pyPdf import PdfFileWriter, PdfFileReader

def append_pdf(input,output):
    [output.addPage(input.getPage(page_num)) for page_num in range(input.numPages)]

output = PdfFileWriter()

append_pdf(PdfFileReader(file("C:\\sample.pdf","rb")),output)
append_pdf(PdfFileReader(file("c:\\sample1.pdf","rb")),output)
append_pdf(PdfFileReader(file("c:\\sample2.pdf","rb")),output)
append_pdf(PdfFileReader(file("c:\\sample3.pdf","rb")),output)

    output.write(file("c:\\combined.pdf","wb"))
Mark K
fuente
0

Una ligera variación usando un diccionario para una mayor flexibilidad (por ejemplo, ordenar, deducir):

import os
from PyPDF2 import PdfFileMerger
# use dict to sort by filepath or filename
file_dict = {}
for subdir, dirs, files in os.walk("<dir>"):
    for file in files:
        filepath = subdir + os.sep + file
        # you can have multiple endswith
        if filepath.endswith((".pdf", ".PDF")):
            file_dict[file] = filepath
# use strict = False to ignore PdfReadError: Illegal character error
merger = PdfFileMerger(strict=False)

for k, v in file_dict.items():
    print(k, v)
    merger.append(v)

merger.write("combined_result.pdf")
Ogaga Uzoh
fuente
0

Usé pdf unite en el terminal de Linux aprovechando el subproceso (se supone que one.pdf y two.pdf existen en el directorio) y el objetivo es fusionarlos en three.pdf

 import subprocess
 subprocess.call(['pdfunite one.pdf two.pdf three.pdf'],shell=True)
usuario8291021
fuente