PDF操作の定番であるPyPDF2のモジュールを利用してフォルダ配下のPDFを連結し、pdfrwでページ番号を付与する手順をまとめました。 pdf の連結には関数を定義することで、汎用性のあるコードです。ひとつにまとめたPDFにページ番号を付与し使いやすくしています。 PythonでのPDF操作の参考になれば幸いです。


PyPDF2とpdfrw をインストールする

PDF 連結にはPyPDF2を利用します。 また、ページ番号の付番にはpdfrwを利用します。 いずれも、通常のPIPコマンド pip install PyPDF2 及び pip install pdfrwでインストール可能です。

ブログにまとめるにあたり、以下の環境で記事を書いています。

  • PyPDF2 3.0.1
  • pdfrw 0.4
  • python 3.9.13
  • Windows 11

PyCharm 2022.3.1 (Community Edition) を利用しています。


完成形のイメージ

このブログで作成するアウトプットの完成形のイメージは以下のとおりです。 2ステップで作成しています。

3page_pdf_sample


Input 及び Output file

サンプルコードで連結するpdfファイルは以下のsourceフォルダに存在します。

C:/Users/usr/sample/data/source

連結、ページ番号が付与されたpdfファイルは以下になります。

C:/Users/usr/sample/data/output/concatenated.pdf


サンプルコード

以下がサンプルコードになります。まず連結部分のサンプルコードをご紹介します。 Python, pypdfでPDFを結合・分割(ファイル全体・個別ページ)を参考に本コードでは本サイトで紹介したPyPDF2を使ったPDFからのテキストファイルの抽出で利用したPyPDF2使っています。

連結するpdfが置いてあるpdfのフォルダと連結後のpdfの二つを引数とする関数(merge_pdf)は同様です。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from PyPDF2 import PdfWriter
from PyPDF2 import PdfReader
import glob
import os
merger = PdfWriter()
def merge_pdf(src_path, dst_file):
    lst = glob.glob(os.path.join(src_path, '*.pdf'))
    lst.sort()
    for p in lst:
        merger.append(p)
    merger.write(dst_file)
    merger.close()
merge_pdf('C://Users//usr//sample//data//source', 
          'C://Users//usr//sample//data//output//concatenated.pdf')

各ステップの説明

  1. PyPDF2 からPdfWriter をインポートします。
  2. PyPDF2 からPdfReader をインポートします。
  3. glob をインポートします。
  4. osをインポートします。
  5. PdfWriter() を mergerというオブジェクト名で定義します。
  6. 関数名 merge_pdfを定義します。引数は2つで src_path が入力となるpdfが格納されているフォルダ名(絶対パスを想定しています)とその出力となる pdf名が引数です。
  7. リスト型式の変数lstsrc_path配下の拡張子pdfのすべてのファイルをglobで代入します。
  8. ファイル名を昇順でソートします * 読み込むファイル名を管理しやすいように命名しておくといいですね。
  9. lstの中身を一つずつ取り出します。取り出すファイルをそれぞれpとしています。
  10. merger オブジェクトで取り出した順にappend (追加)します。
  11. dst_file という名前でWriteします。
  12. close して終了します。 ここまでが、関数の中身です。
  13. 'C://Users//usr//sample//data//source''C://Users//usr//sample//data//output//concatenated.pdf'を引数としたmerge_pdf関数を実行し、pdfファイルを連結します。

ページ番号を追加する

ページ番号をフッターに追加するには、pdfrwを利用します。

reportlab-how-to-add-a-footer-to-a-pdf-fileを参考にしています。

アウトプットイメージは以下のとおりです。

2page_pdf_sample


サンプルコード

以下がサンプルコードになります。殆どreportlab-how-to-add-a-footer-to-a-pdf-fileのままを載せています。

ページ数を付与するファイルを置いているディレクトリをカレントディレクトリとしているため、ファイル名のみを指定しています。 ステップ1で連結したconcatenated.pdfをinput_file にしています。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
from reportlab.pdfgen.canvas import Canvas
from pdfrw import PdfReader
from pdfrw.toreportlab import makerl
from pdfrw.buildxobj import pagexobj
import sys
import os

input_file = "concatenated.pdf"
output_file = "concatenated_pgn.pdf"


# Get pages
reader = PdfReader(input_file)
pages = [pagexobj(p) for p in reader.pages]


# Compose new pdf
canvas = Canvas(output_file)

for page_num, page in enumerate(pages, start=1):

    # Add page
    canvas.setPageSize((page.BBox[2], page.BBox[3]))
    canvas.doForm(makerl(canvas, page))

    # Draw footer
    footer_text = "Page %s of %s" % (page_num, len(pages))
    x = 128
    canvas.saveState()
    canvas.setStrokeColorRGB(0.941, 0.694, 0.024) # line color : gold
    canvas.setFillColorRGB(0.02, 0.412, 0.58)  #  character color : blue
    canvas.setLineWidth(2.0)
    canvas.line(66, 78, page.BBox[2] - 66, 78)
    canvas.setFont('Helvetica', 10.5)
    #canvas.setFont('Times-Roman', 10.5)
    canvas.drawString(page.BBox[2]-x, 65, footer_text)
    canvas.restoreState()

    canvas.showPage()

canvas.save()

[ここがポイント!]

  1. ディレクトリの指定は'C://Users//usr//sample//data//source' のとおり、本環境では//とスラッシュを重ねないと上手く稼働しませんでした。
  2. 線の色と字の色の指定はRGB(各々0~1までの値)で行っています。
  3. フォントは、’Helvetica’と’Times-Roman’のいずれかが指定可能です。

参照ページ一覧

このブログを作成するにあたり、以下のページを参考にさせていただきました。併せてご覧ください。

1) Python, pypdfでPDFを結合・分割(ファイル全体・個別ページ)
2) reportlab-how-to-add-a-footer-to-a-pdf-file
3) PyPDF2を使ったPDFからのテキストファイルの抽出