1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

PythonでJSONデータからPDFドキュメントを生成

1
Last updated at Posted at 2026-07-10

企業の日常業務において、JSON形式のデータはAPI連携、設定ファイル、データ交換など幅広い場面で活用されています。しかし、構造化されたJSONデータを読みやすく配布可能なPDFレポートに変換するには、手動でのコピー&ペーストや複雑なテンプレートツールの使用が必要で、非効率なだけでなく、フォーマットの崩れやデータの欠落等问题も発生しがちです。財務レポート、進捗報告書、顧客情報サマリーなどを定期的に作成する必要がある場合、PDFドキュメントの自動生成は業務効率化の鍵となります。

本記事では、Pythonを使用してJSONデータからフォーマット整ったPDFドキュメントを自動生成する方法を紹介します。このプロセスは完全に自動化されており、人的介入が不要で、業務レポートの作成、データアーカイブ、契約書類の添付、APIデータの可視化など、さまざまなユースケースに適用できます。コードによるアプローチにより、ドキュメントのレイアウト、フォントスタイル、テーブル構造、ページ要素を柔軟に制御でき、プロフェッショナルで見栄えの良いPDFを作成することができます。

本記事で紹介する方法には Free Spire.PDF for Python が必要です。pipでインストールできます:

pip install spire.pdf.free

1. JSONデータの準備とPDFドキュメントの作成

PDF生成を始める前に、サンプルJSONデータを定義し、PDFドキュメントオブジェクトを初期化します。ここでは、製品情報、販売記録、統計サマリーを含む販売データレポートを例として使用します。

import json
from spire.pdf import PdfDocument, PdfPageBase
from spire.pdf.graphics import *

# サンプルJSONデータ
json_data = """
{
    "report_title": "2024年第1四半期販売レポート",
    "company": "株式会社ABCテクノロジー",
    "date": "2024年3月31日",
    "summary": {
        "total_sales": 1580000,
        "total_orders": 342,
        "average_order_value": 4619.88
    },
    "products": [
        {"name": "ノートパソコン", "category": "電子機器", "quantity": 120, "unit_price": 89990, "total": 10798800},
        {"name": "ワイヤレスマウス", "category": "アクセサリー", "quantity": 450, "unit_price": 2980, "total": 1341000},
        {"name": "メカニカルキーボード", "category": "アクセサリー", "quantity": 280, "unit_price": 12800, "total": 3584000},
        {"name": "モニター", "category": "電子機器", "quantity": 95, "unit_price": 45800, "total": 4351000},
        {"name": "USBハブ", "category": "アクセサリー", "quantity": 600, "unit_price": 1980, "total": 1188000}
    ]
}
"""

# JSONデータを解析
data = json.loads(json_data)

# PDFドキュメントを作成
doc = PdfDocument()
page = doc.Pages.Add()

説明:

  • json.loads() はJSON文字列をPython辞書型に変換し、後続のデータ抽出を容易にします。
  • PdfDocument() はPDFドキュメントオブジェクトを作成し、Pages.Add() でコンテンツの载体となる新規ページを追加します。
  • サンプルデータにはレポートタイトル、会社情報、統計サマリー、製品リストが含まれており、実際のビジネスシーンを模倣しています。

この段階でデータ準備とドキュメント初期化が完了し、後続のコンテンツ描画の基盤が整いました。


2. ドキュメントヘッダーと会社情報の描画

次に、PDFページの上部にレポートタイトルと基本情報を描画し、ドキュメント全体のフレームワークを構築します。

def draw_header(page, data):
    """ドキュメントヘッダーと会社情報を描画"""
    # ページ余白を設定
    margin_left = 50
    margin_top = 50
    y_position = margin_top
    
    # 会社名を描画
    company_font = PdfTrueTypeFont("Arial", 14.0, PdfFontStyle.Bold, True)
    company_brush = PdfSolidBrush(PdfRGBColor(Color.get_DarkGray()))
    page.Canvas.DrawString(
        data["company"], 
        company_font, 
        company_brush, 
        margin_left, 
        y_position
    )
    y_position += 25
    
    # レポートタイトルを描画
    title_font = PdfTrueTypeFont("Arial", 24.0, PdfFontStyle.Bold, True)
    title_brush = PdfSolidBrush(PdfRGBColor(Color.get_Navy()))
    title_format = PdfStringFormat(PdfTextAlignment.Left)
    page.Canvas.DrawString(
        data["report_title"], 
        title_font, 
        title_brush, 
        margin_left, 
        y_position, 
        title_format
    )
    y_position += 35
    
    # 日付を描画
    date_font = PdfTrueTypeFont("Arial", 11.0, PdfFontStyle.Regular, True)
    date_brush = PdfSolidBrush(PdfRGBColor(Color.get_Gray()))
    page.Canvas.DrawString(
        f"レポート作成日:{data['date']}", 
        date_font, 
        date_brush, 
        margin_left, 
        y_position
    )
    
    return y_position + 30

# ヘッダー描画関数を呼び出し
current_y = draw_header(page, data)

説明:

  • PdfTrueTypeFont はフォントの種類、サイズ、スタイル(太字、斜体など)を設定するために使用します。
  • PdfSolidBrush はテキストの色を定義し、RGBカラースペースをサポートします。
  • DrawString メソッドは指定された座標位置にテキストを描画し、PdfStringFormat と組み合わせて配置方法を設定できます。
  • y_position 変数を増分させることで、コンテンツの垂直レイアウトを実現し、重複を回避します。

このステップでドキュメントの視覚的階層が確立され、読者はレポートの基本情報を迅速に把握できます。


3. 統計サマリー情報の描画

タイトルの下に、主要なビジネス統計データを表示し、核心的な指標を簡潔に提示します。

def draw_summary(page, data, y_position):
    """統計サマリーを描画"""
    margin_left = 50
    summary = data["summary"]
    
    # サマリータイトルを描画
    section_font = PdfTrueTypeFont("Arial", 16.0, PdfFontStyle.Bold, True)
    section_brush = PdfSolidBrush(PdfRGBColor(Color.get_Black()))
    page.Canvas.DrawString(
        "販売サマリー", 
        section_font, 
        section_brush, 
        margin_left, 
        y_position
    )
    y_position += 30
    
    # サマリー内容を描画
    content_font = PdfTrueTypeFont("Arial", 11.0, PdfFontStyle.Regular, True)
    content_brush = PdfSolidBrush(PdfRGBColor(Color.get_Black()))
    
    summary_items = [
        f"総売上高:¥{summary['total_sales']:,.2f}",
        f"注文总数:{summary['total_orders']}",
        f"平均注文額:¥{summary['average_order_value']:,.2f}"
    ]
    
    for item in summary_items:
        page.Canvas.DrawString(
            item, 
            content_font, 
            content_brush, 
            margin_left, 
            y_position
        )
        y_position += 22
    
    return y_position + 20

# サマリー描画関数を呼び出し
current_y = draw_summary(page, data, current_y)

説明:

  • f-string を使用して数値をフォーマットし、:, で桁区切りを追加、.2f で小数点以下2桁を表示します。
  • サマリー情報は逐行配置し、各情報の間隔を22単位に設定して視覚的な快適さを保ちます。
  • フォントサイズはタイトルより小さく、本文より大きく設定し、明確な情報階層を形成します。

この部分でレポートの核心データが強調され、読者は業務概要を迅速に把握できます。


4. 製品明細テーブルの作成

テーブルは構造化データを表示するための最適な方法です。JSONの製品リストをPDFテーブルに変換し、ヘッダー行とデータ行を含めます。

def draw_product_table(page, data, y_position):
    """製品明細テーブルを描画"""
    margin_left = 50
    products = data["products"]
    
    # テーブルタイトルを描画
    table_title_font = PdfTrueTypeFont("Arial", 16.0, PdfFontStyle.Bold, True)
    table_title_brush = PdfSolidBrush(PdfRGBColor(Color.get_Black()))
    page.Canvas.DrawString(
        "製品明細", 
        table_title_font, 
        table_title_brush, 
        margin_left, 
        y_position
    )
    y_position += 30
    
    # テーブル列を定義
    columns = ["製品名", "カテゴリ", "数量", "単価", "合計金額"]
    column_widths = [120, 100, 80, 100, 100]
    
    # ヘッダーを描画
    header_font = PdfTrueTypeFont("Arial", 11.0, PdfFontStyle.Bold, True)
    header_brush = PdfSolidBrush(PdfRGBColor(Color.get_White()))
    header_bg_brush = PdfSolidBrush(PdfRGBColor(Color.get_Navy()))
    
    x_position = margin_left
    for i, col in enumerate(columns):
        # ヘッダー背景を描画
        rect = RectangleF(x_position, y_position, column_widths[i], 25)
        page.Canvas.DrawRectangle(header_bg_brush, rect)
        # ヘッダーテキストを描画
        page.Canvas.DrawString(
            col, 
            header_font, 
            header_brush, 
            x_position + 5, 
            y_position + 5
        )
        x_position += column_widths[i]
    
    y_position += 25
    
    # データ行を描画
    row_font = PdfTrueTypeFont("Arial", 10.0, PdfFontStyle.Regular, True)
    row_brush = PdfSolidBrush(PdfRGBColor(Color.get_Black()))
    alternate_brush = PdfSolidBrush(PdfRGBColor(Color.get_LightGray()))
    
    for idx, product in enumerate(products):
        # 交互に行背景色を変更
        if idx % 2 == 0:
            bg_brush = PdfSolidBrush(PdfRGBColor(Color.get_White()))
        else:
            bg_brush = alternate_brush
        
        x_position = margin_left
        row_height = 22
        
        # 行背景を描画
        row_rect = RectangleF(margin_left, y_position, sum(column_widths), row_height)
        page.Canvas.DrawRectangle(bg_brush, row_rect)
        
        # セルデータを描画
        cell_data = [
            product["name"],
            product["category"],
            str(product["quantity"]),
            f"¥{product['unit_price']:,}",
            f"¥{product['total']:,}"
        ]
        
        for i, cell_value in enumerate(cell_data):
            page.Canvas.DrawString(
                cell_value, 
                row_font, 
                row_brush, 
                x_position + 5, 
                y_position + 4
            )
            x_position += column_widths[i]
        
        y_position += row_height
    
    # テーブル枠線を描画
    border_pen = PdfPen(PdfRGBColor(Color.get_Black()), 0.5)
    table_width = sum(column_widths)
    table_height = 25 + len(products) * 22
    
    # 外枠
    page.Canvas.DrawRectangle(
        border_pen, 
        RectangleF(margin_left, y_position - table_height, table_width, table_height)
    )
    
    # 横線
    for i in range(len(products) + 2):
        line_y = y_position - table_height + i * 22 if i > 0 else y_position - table_height
        if i == 0:
            line_y = y_position - table_height
        elif i == 1:
            line_y = y_position - table_height + 25
        else:
            line_y = y_position - table_height + 25 + (i - 1) * 22
        
        page.Canvas.DrawLine(
            border_pen, 
            margin_left, 
            line_y, 
            margin_left + table_width, 
            line_y
        )
    
    # 縦線
    x_pos = margin_left
    for width in column_widths:
        page.Canvas.DrawLine(
            border_pen, 
            x_pos, 
            y_position - table_height, 
            x_pos, 
            y_position
        )
        x_pos += width
    page.Canvas.DrawLine(
        border_pen, 
        x_pos, 
        y_position - table_height, 
        x_pos, 
        y_position
    )
    
    return y_position + 30

# テーブル描画関数を呼び出し
current_y = draw_product_table(page, data, current_y)

説明:

  • テーブルはヘッダーに濃い背景色、白色テキストを採用し、可読性を向上させています。
  • データ行は交互に背景色(白と薄灰色)を使用し、視覚的な識別性を高めています。
  • RectangleF は矩形領域を描画するために使用され、セルの背景と枠線として機能します。
  • DrawLine メソッドはテーブルの横線と縦線を描画し、完全なグリッド構造を形成します。
  • 列幅はコンテンツの長さに応じて適切に配分され、データの完全表示と適切な余白を確保しています。

このステップでJSON配列が構造化されたテーブルに変換され、データ可視化の核心部分となります。


5. フッター情報の追加

最後に、ページ下部にフッターを追加し、ページ番号と著作権情報を含めて、ドキュメントをより完全でプロフェッショナルなものにします。

def draw_footer(page, page_number, total_pages):
    """フッターを描画"""
    page_width = page.Canvas.ClientSize.Width
    margin_bottom = 30
    
    # 区切り線を描画
    line_pen = PdfPen(PdfRGBColor(Color.get_LightGray()), 0.5)
    page.Canvas.DrawLine(
        line_pen, 
        50, 
        page.Canvas.ClientSize.Height - margin_bottom - 15, 
        page_width - 50, 
        page.Canvas.ClientSize.Height - margin_bottom - 15
    )
    
    # ページ番号を描画
    footer_font = PdfTrueTypeFont("Arial", 9.0, PdfFontStyle.Regular, True)
    footer_brush = PdfSolidBrush(PdfRGBColor(Color.get_Gray()))
    footer_format = PdfStringFormat(PdfTextAlignment.Center)
    
    page_text = f"{page_number} ページ / 全 {total_pages} ページ"
    page.Canvas.DrawString(
        page_text, 
        footer_font, 
        footer_brush, 
        page_width / 2, 
        page.Canvas.ClientSize.Height - margin_bottom, 
        footer_format
    )
    
    # 著作権情報を描画
    copyright_text = "© 2024 株式会社ABCテクノロジー - 社内資料、外部持ち出し禁止"
    page.Canvas.DrawString(
        copyright_text, 
        footer_font, 
        footer_brush, 
        page_width / 2, 
        page.Canvas.ClientSize.Height - margin_bottom + 15, 
        footer_format
    )

# フッター描画関数を呼び出し(単一ページドキュメント)
draw_footer(page, 1, 1)

説明:

  • フッターには水平区切り線、ページ番号、著作権声明が含まれ、ビジネスドキュメントの規範に準拠しています。
  • 中央揃えを使用して、フッターが視覚的にバランス良く美しく配置されます。
  • フォントは小さく、色は薄く設定され、主要コンテンツの閲覧を妨げません。

6. PDFドキュメントの保存

すべてのコンテンツ描画が完了したら、PDFファイルを指定のパスに保存します。

output_file = "販売レポート.pdf"
doc.SaveToFile(output_file)
doc.Close()

print(f"PDFドキュメントを生成しました:{output_file}")

説明:

  • SaveToFile メソッドはメモリ内のPDFドキュメントをファイルシステムに保存します。
  • Close メソッドはドキュメントリソースを解放し、ファイルの完全性を確保します。
  • 生成されたPDFは直接開いて閲覧、印刷、またはメールで送信できます。

生成結果のプレビュー

以下は、生成された結果のプレビュー画像です:

PythonでJSONデータからPDFドキュメントを生成


主要クラスとメソッドの解説

参照および拡張を容易にするため、本記事で使用した主要なクラス、メソッド、プロパティを整理します。

主要クラスの説明

クラス名 説明
PdfDocument PDFドキュメントオブジェクト、ドキュメント全体のライフサイクルを管理
PdfPageBase ページオブジェクト、コンテンツ描画用のキャンバスを提供
PdfTrueTypeFont フォントクラス、フォント名、サイズ、スタイルを設定
PdfSolidBrush ブラシクラス、塗りつぶし色を定義
PdfPen ペンクラス、線の色と幅を定義
PdfStringFormat テキストフォーマットクラス、配置方法、文字間隔などを設定
RectangleF 矩形構造体、描画領域を定義
PdfRGBColor 色クラス、RGBカラーモードをサポート

主要メソッドの説明

メソッド 説明 パラメータ例
doc.Pages.Add() 新規ページを追加 なし
page.Canvas.DrawString() キャンバスにテキストを描画 (text, font, brush, x, y, format)
page.Canvas.DrawRectangle() 矩形を描画(塗りつぶしまたは枠線) (brush/pen, rectangle)
page.Canvas.DrawLine() 直線を描画 (pen, x1, y1, x2, y2)
doc.SaveToFile() ドキュメントをファイルに保存 (filename)
doc.Close() ドキュメントを閉じてリソースを解放 なし

フォントとスタイルの設定

# フォントを作成
font = PdfTrueTypeFont("Arial", 12.0, PdfFontStyle.Bold, True)
# パラメータ:フォント名、フォントサイズ、スタイル(Bold/Italic/Regular/Underline)、埋め込みフラグ

# ブラシを作成
brush = PdfSolidBrush(PdfRGBColor(Color.get_Navy()))
# サポートされる色:get_Black(), get_White(), get_Red(), get_Blue(), get_Navy() など

# ペンを作成
pen = PdfPen(PdfRGBColor(Color.get_Black()), 0.5)
# パラメータ:色、線の幅

# テキストフォーマットを設定
format = PdfStringFormat(PdfTextAlignment.Center, PdfVerticalAlignment.Middle)
# 配置方法:Left, Center, Right, Justify

レイアウトテクニック

  • 垂直レイアウト:y座標を増分させることで、コンテンツを上から下へ配置
  • 水平レイアウト:x座標を増分させることで、コンテンツ从左から右へ配置
  • 余白制御margin_leftmargin_top などの変数を設定して余白を一括管理
  • 間隔調整:フォントの高さとコンテンツの重要性に応じて行間隔を調整

拡張アプリケーションシーン

本記事の基本的な実装に基づき、以下の機能をさらに拡張できます:

1. 複数ページのサポート

データ量が多い場合、自動ページ分割が必要です:

# コンテンツがページ高さを超えるかどうかを検出
if current_y > page.Canvas.ClientSize.Height - 100:
    page = doc.Pages.Add()  # 新規ページを追加
    current_y = 50  # y座標をリセット

2. ファイルからJSONを読み込む

with open('sales_data.json', 'r', encoding='utf-8') as f:
    data = json.load(f)

3. チャート可視化の追加

Spire.PDFのグラフィック機能と組み合わせ、棒グラフ、円グラフなどを描画:

# 簡単な棒グラフを描画
for i, product in enumerate(products):
    bar_height = product['total'] / 10000  # スケール比率
    bar_rect = RectangleF(margin_left + i * 60, chart_y, 50, bar_height)
    page.Canvas.DrawRectangle(bar_brush, bar_rect)

4. レポートの一括生成

複数のJSONファイルを巡回し、異なる部門や期間ごとに独立したレポートを生成:

import glob
for json_file in glob.glob('reports/*.json'):
    with open(json_file, 'r') as f:
        data = json.load(f)
    generate_pdf(data, f"report_{json_file}.pdf")

5. カスタムテンプレートシステム

レイアウトロジックをテンプレートクラスにカプセル化し、動的な設定をサポート:

class PDFTemplate:
    def __init__(self, config):
        self.font_config = config['fonts']
        self.color_scheme = config['colors']
        self.layout = config['layout']
    
    def render(self, data):
        # 設定に基づいてPDFをレンダリング
        pass

まとめ

本記事の例を通じて、Pythonを使用してJSONデータからプロフェッショナルなPDFドキュメントを自動生成する方法を習得できました。JSONデータ構造の解析から、タイトル、サマリー、テーブル、フッターの描画まで、全体のプロセスは完全に自動化されており、業務レポート、データアーカイブ、ドキュメント配布などのシーンに特に適しています。

手動でPDFを作成する方法と比較して、コードベースのアプローチには顕著な優位性があります:

  • 効率性:ワンクリックで生成、繰り返し作業が不要
  • 一貫性:統一されたフォーマットとスタイルで、プロフェッショナルなイメージを維持
  • 柔軟性:データに応じてコンテンツとレイアウトを動的に調整可能
  • 拡張性:既存のシステムやワークフローに簡単に統合

在此基础上、ウォーターマークの追加、ドキュメントの暗号化、画像の挿入、目次の生成など、より高度な機能を探索し、企業レベルのドキュメント自動化のための完全なソリューションを提供できます。大量の構造化データを処理したり、標準化されたレポートを定期的に生成する必要がある場合、PythonとSpire.PDFに基づくこのソリューションは業務効率を大幅に向上させます。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?