ここでは
のプロジェクトコードの詳細を初心者の方にも分かりやすく解説します。
コードをの動きを試したい方、以下のサンプルファイルを使って下さい
内容は:
1_dummy_table_3pages.pdf
- 1ページ目:テーブルあり
- 2ページ目:別形式のテーブル(分割、改行された行あり) → 行の揺れ
- 3ページ目:1行のテーブル → ページがなくなる
2_dummy_table_3pages.pdf
- 1ページ目:テーブルなし → ページの揺れ
- 2ページ目:テーブルあり
- 3ページ目:テーブルあり
これらのファイルのテーブルをどのように処理するか?
1.サンプル PDF をダウンロードする
以下の 2 つの PDF を GitHub に置いてあります。
クリックするとブラウザから直接ダウンロードできます。
ダウンロードボタンをクリックするだけ!
2. ダウンロードした PDF を同じフォルダに入れる
C:/Users/あなたの名前/Desktop/Hongo2_C190/
├── 1_dummy_table_3pages.pdf
└── 2_dummy_table_3pages.pdf
フォルダ名は自由ですが、
日本語を含まないパス にしておくとトラブルが少なくなります。
3. フォルダを Desktop に配置する
作成したフォルダを デスクトップに置く と、
Python からパスを指定しやすくなります。
C:/Users/あなたの名前/Desktop/Hongo2_C190/
4. コードの src_dir にフォルダのパスを設定する
コード内の Config の部分を開きます。
config = Config(
src_dir=Path(r"C:/Users/あなたの名前/Desktop/Hongo2_C190"),
dst_dir=Path(r"C:/Users/あなたの名前/Desktop/Qiita_投稿_Hongo/Collection_Hongo"),
file_slice=slice(None),
page_slice=slice(0,1),
row_slice=slice(1, 2),
output_csv='Smart_extracted5.csv'
)
✔ 変更するのは src_dir の 1 行だけ
※ バックスラッシュ \ の代わりに、スラッシュ / を使ってください。
Python では / の方が安全です。
この記事で分かること
- 実務で採用するpythonチュートリアル
- プロジェクト全体の実行フロー
- Config クラスの役割
- 関数定義と実行の違い
- main() から convert_pdfs が呼ばれるまでの流れ
ここは初心者向きですので関数実行のフローが見えてる方はスキップして下さい
AIのClaudeサン、Copilotサンのお手伝い頂きました
1. :convert_pdfを呼び出すまで
コード全体の構造
┌────────────────────────────────────────────────┐
│ 1. ログ設定(プログラム起動時に1回だけ)
├────────────────────────────────────────────────
│ 2. Configクラスの定義
├────────────────────────────────────────────────
│ 3. 関数定義(prepare_files, extract_table等)
├────────────────────────────────────────────────
│ 4. メイン処理(if __name__ == "__main__":)
│ ├─ Configインスタンス作成
│ ├─ convert_pdfs(config) 呼び出し
│ └─ cleanup(config.dst_dir) 呼び出し
└────────────────────────────────────────────────┘
🎬 実行の流れ(ステップバイステップ)
ステップ1️⃣ インポート文の実行(最初の方)
import logging
from pathlib import Path
from dataclasses import dataclass
import shutil
...
ステップ2️⃣ログ設定の実行
# ===== ログ設定 =====
logging.basicConfig(
level=logging.INFO,
format='[%(levelname)s] %(message)s',
handlers=[
logging.FileHandler("log.txt", encoding="utf-8"),
logging.StreamHandler(),
]
)
logger = logging.getLogger(__name__)
何が起こる?
┌─────────────────────────────────────┐
│ ログシステムの初期設定
├─────────────────────────────────────
│ ✅ ログレベル: INFO
│ ✅ 出力形式: [INFO] メッセージ
│ ✅ 出力先1: log.txt ファイル
│ ✅ 出力先2: コンソール(画面)
└─────────────────────────────────────┘
↓
logger という名前のロガーを作成
↓
これ以降、logger.info("...") でログ出力できる
ステップ3️⃣ Configクラスの定義
@dataclass
class Config:
src_dir: Path
dst_dir: Path
file_slice: slice
page_slice: slice
row_slice: slice
output_csv: str
何が起こる?
Configという「設計図」を定義
↓
まだインスタンス(実体)は作られていない
↓
「こういう構造のデータを保存できますよ」という定義だけ
イメージ:
設計図: Config
┌──────────────────┐
│ src_dir: Path │ ← PDFの元フォルダ
│ dst_dir: Path │ ← 作業フォルダ
│ file_slice: slice│ ← ファイル範囲
│ page_slice: slice│ ← ページ範囲
│ row_slice: slice │ ← 行範囲
│ output_csv: str │ ← 出力ファイル名
└──────────────────┘
ステップ5️⃣: 関数定義(prepare_files, extract_table等)
def prepare_files(config: Config) -> list[Path]:
"""PDFファイルを作業フォルダに移動"""
...
def extract_table(...):
...
def create_df(...):
...
def convert_pdfs(config: Config):
...
何が起こる?
関数の「定義」だけが行われる
↓
まだ実行はされない!
↓
「こういう処理ができますよ」という登録だけ
関数は呼び出されて初めて実行されます
イメージ:
```text
関数リスト(まだ実行されていない)
├─ prepare_files() ← PDFファイル準備
├─ extract_table() ← データ抽出
├─ create_df() ← DataFrame作成
└─ convert_pdfs() ← メイン処理
全部「待機中」の状態
ステップ5️⃣: メイン処理に到達
if __name__ == "__main__":
# ここから実行開始!
if name == "main": の意味
このファイルが直接実行された場合のみ、以下を実行
↓
他のファイルからimportされた場合は実行しない
↓
「このファイルをメインとして実行したとき」という条件
いまいちの理解の方
👇
ステップ6️⃣: Configインスタンスの作成
config = Config(
src_dir=Path(r"C:/Users/xxx/Desktop/Hongo_C190"),
dst_dir=Path(r"C:/Users/xxx/Desktop/PythonProject/Collection_Hongo"),
file_slice=slice(None), # 全ファイル
page_slice=slice(0, 1), # 1ページ目のみ
row_slice=slice(1, 2), # 2行目のみ
output_csv='Smart_extracted.csv'
)
何が起こる:
設計図(Config)を使って、実体(インスタンス)を作成
↓
具体的な値を設定
視覚化:
【ステップ4で作った設計図】
Config (設計図)
┌──────────────────┐
│ src_dir: Path │
│ dst_dir: Path │
│ ... │
└──────────────────┘
↓ 値を入れて実体化
【今作ったインスタンス】
config (実体)
┌────────────────────────────────────────────┐
│ src_dir: C:/Users/xxx/Desktop/Hongo_C190 │
│ dst_dir: C:/.../Collection_Hongo │
│ file_slice: slice(None, None, None) │
│ page_slice: slice(0, 1, None) │
│ row_slice: slice(1, 2, None) │
│ output_csv: 'Smart_extracted.csv' │
└────────────────────────────────────────────┘
各設定の意味:
src_dir = C:/Users/godel/Desktop/Hongo_C190
↓
元のPDFファイルがあるフォルダ
dst_dir = C:/.../Collection_Hongo
↓
作業用フォルダ(ここにPDFをコピーして処理)
file_slice = slice(None)
↓
全ファイルを処理(制限なし)
page_slice = slice(0, 1)
↓
各PDFの1ページ目のみ抽出
0から始まって1の手前まで = 0番目 = 1ページ目
row_slice = slice(1, 2)
↓
テーブルの2行目のみ抽出
1から始まって2の手前まで = 1番目 = 2行目
output_csv = 'Smart_extracted.csv'
↓
出力ファイル名
サンプルPDFファイルを使ってsliceの値を変更して試して!
ステップ7️⃣: convert_pdfs(config) の呼び出し
convert_pdfs(config)
ここで初めて処理が始まる!
PdfPlumber 大量pPDFファイル一括処理:行が揺れてるPDF:コード解説_2に続く