「PDFファイルから特定のテキストや要素の位置を取得したい」「PDF内の座標情報を使って自動処理を行いたい」そんなニーズを持つ開発者の方は多いのではないでしょうか?
PDF座標取得は、文書解析やデータ抽出の自動化において重要な技術です。請求書の金額欄を自動で読み取ったり、フォームの入力位置を特定したりする際に欠かせない機能なんです。
今回は、Pythonを使ってPDFから座標情報を取得する方法を、初心者の方でも分かりやすく解説していきます。基本的な使い方から実践的な応用例まで、詳しくご紹介しますね。
PDF座標取得の基本概念

PDF座標系の仕組み
PDFファイルでは、独特の座標系が使われています。
基本的な座標系
- 原点(0, 0)は通常ページの左下角
- X軸は右方向が正
- Y軸は上方向が正
- 単位はポイント(1ポイント = 1/72インチ)
実際のサイズ例
- A4サイズ:約595 × 842ポイント
- レターサイズ:約612 × 792ポイント
- B5サイズ:約516 × 729ポイント
この座標系を理解することで、正確な位置情報を取得できるようになります。
座標取得が必要な場面
PDF座標取得は、以下のような場面で活用されています:
データ抽出の自動化
- 請求書の金額や日付の自動読み取り
- 契約書の署名欄の位置特定
- 表組みデータの構造化抽出
フォーム処理
- 入力フィールドの位置確認
- チェックボックスの状態取得
- ボタンやリンクの座標取得
実際に、多くの企業でこれらの技術が業務効率化に活用されています。
PyPDF2を使った基本的な座標取得
PyPDF2のインストールと基本設定
まずは、最も基本的なライブラリであるPyPDF2から始めましょう。
インストール方法
pip install PyPDF2
基本的なPDFファイルの読み込み
import PyPDF2
# PDFファイルを開く
with open('sample.pdf', 'rb') as file:
pdf_reader = PyPDF2.PdfReader(file)
# ページ数を確認
num_pages = len(pdf_reader.pages)
print(f"ページ数: {num_pages}")
# 最初のページを取得
first_page = pdf_reader.pages[0]
この基本コードで、PDFファイルの読み込みと基本情報の取得ができます。
テキストの座標情報を取得する方法
PyPDF2では、テキストとその位置情報を取得できます。
テキスト抽出と座標取得のコード例
def get_text_coordinates(pdf_path):
with open(pdf_path, 'rb') as file:
pdf_reader = PyPDF2.PdfReader(file)
page = pdf_reader.pages[0] # 最初のページ
# ページサイズを取得
page_box = page.mediabox
width = float(page_box.width)
height = float(page_box.height)
print(f"ページサイズ: {width} × {height} ポイント")
# テキストを抽出
text = page.extract_text()
print(f"抽出されたテキスト: {text}")
return width, height, text
# 使用例
width, height, text = get_text_coordinates('sample.pdf')
ただし、PyPDF2では詳細な座標情報の取得に限界があるため、より高度な処理にはpdfplumberがおすすめです。
pdfplumberを使った高精度座標取得
pdfplumberの特徴とインストール
pdfplumberは、PDF座標取得において最も人気の高いライブラリです。
インストール方法
pip install pdfplumber
主な特徴
- 高精度なテキスト座標取得
- 表組みの自動認識
- 画像や図形の位置情報取得
- 直感的なAPI設計
詳細な座標情報を取得するコード
pdfplumberを使った具体的な座標取得方法をご紹介します。
基本的な座標取得コード
import pdfplumber
def extract_text_with_coordinates(pdf_path):
with pdfplumber.open(pdf_path) as pdf:
# 最初のページを処理
page = pdf.pages[0]
# ページサイズを取得
width = page.width
height = page.height
print(f"ページサイズ: {width} × {height}")
# テキストの座標情報を取得
for char in page.chars:
print(f"文字: '{char['text']}'")
print(f"座標: x0={char['x0']:.2f}, y0={char['y0']:.2f}")
print(f" x1={char['x1']:.2f}, y1={char['y1']:.2f}")
print(f"フォント: {char['fontname']}, サイズ: {char['size']}")
print("---")
# 使用例
extract_text_with_coordinates('sample.pdf')
このコードにより、文字単位での詳細な位置情報が取得できます。
特定テキストの座標を検索する方法
目的のテキストを見つけて、その座標を取得する実用的な方法です。
特定テキスト検索のコード例
def find_text_coordinates(pdf_path, target_text):
with pdfplumber.open(pdf_path) as pdf:
for page_num, page in enumerate(pdf.pages):
# ページ内のすべてのテキスト要素を確認
for word in page.extract_words():
if target_text in word['text']:
print(f"ページ {page_num + 1} で発見:")
print(f"テキスト: '{word['text']}'")
print(f"座標: x0={word['x0']:.2f}, y0={word['y0']:.2f}")
print(f" x1={word['x1']:.2f}, y1={word['y1']:.2f}")
return {
'page': page_num + 1,
'text': word['text'],
'x0': word['x0'],
'y0': word['y0'],
'x1': word['x1'],
'y1': word['y1']
}
print(f"'{target_text}' は見つかりませんでした")
return None
# 使用例
coordinates = find_text_coordinates('invoice.pdf', '合計金額')
この機能により、請求書の金額欄など、特定の項目を効率的に見つけられます。
PyMuPDFを使った高速座標取得
PyMuPDFの特徴
PyMuPDF(fitz)は、高速処理が特徴的なライブラリです。
インストール方法
pip install PyMuPDF
主な利点
- 処理速度が非常に高速
- 画像の座標取得も可能
- ベクター形式の図形にも対応
- メモリ使用量が効率的
PyMuPDFでの座標取得実装
高速な座標取得を実現するコード例をご紹介します。
基本的な実装コード
import fitz # PyMuPDF
def get_coordinates_with_pymupdf(pdf_path):
# PDFドキュメントを開く
doc = fitz.open(pdf_path)
# 最初のページを取得
page = doc[0]
# ページサイズを取得
rect = page.rect
print(f"ページサイズ: {rect.width} × {rect.height}")
# テキストブロックとその座標を取得
text_dict = page.get_text("dict")
for block in text_dict["blocks"]:
if "lines" in block: # テキストブロックの場合
for line in block["lines"]:
for span in line["spans"]:
bbox = span["bbox"] # バウンディングボックス
text = span["text"]
print(f"テキスト: '{text}'")
print(f"座標: x0={bbox[0]:.2f}, y0={bbox[1]:.2f}")
print(f" x1={bbox[2]:.2f}, y1={bbox[3]:.2f}")
print("---")
doc.close()
# 使用例
get_coordinates_with_pymupdf('sample.pdf')
画像や図形の座標取得
PyMuPDFなら、テキスト以外の要素の座標も取得できます。
画像座標取得のコード
def get_image_coordinates(pdf_path):
doc = fitz.open(pdf_path)
page = doc[0]
# 画像リストを取得
image_list = page.get_images()
for img_index, img in enumerate(image_list):
# 画像の詳細情報を取得
xref = img[0]
bbox = page.get_image_bbox(img)
print(f"画像 {img_index + 1}:")
print(f"座標: x0={bbox.x0:.2f}, y0={bbox.y0:.2f}")
print(f" x1={bbox.x1:.2f}, y1={bbox.y1:.2f}")
print(f"サイズ: {bbox.width:.2f} × {bbox.height:.2f}")
print("---")
doc.close()
# 使用例
get_image_coordinates('document_with_images.pdf')
実践的な応用例
請求書の金額自動抽出
実際のビジネスでよく使われる、請求書からの金額抽出システムです。
請求書解析のコード例
import pdfplumber
import re
def extract_invoice_amounts(pdf_path):
amounts = []
with pdfplumber.open(pdf_path) as pdf:
for page in pdf.pages:
# 金額パターンを検索(¥記号 + 数字 + カンマ)
text = page.extract_text()
# 正規表現で金額を検索
amount_pattern = r'¥[\d,]+'
found_amounts = re.findall(amount_pattern, text)
# 座標情報付きで詳細検索
for word in page.extract_words():
if re.search(amount_pattern, word['text']):
amount_info = {
'text': word['text'],
'x': (word['x0'] + word['x1']) / 2,
'y': (word['y0'] + word['y1']) / 2,
'page': page.page_number
}
amounts.append(amount_info)
return amounts
# 使用例
invoice_amounts = extract_invoice_amounts('invoice.pdf')
for amount in invoice_amounts:
print(f"金額: {amount['text']}, 座標: ({amount['x']:.1f}, {amount['y']:.1f})")
表組みデータの構造化抽出
表形式のデータを座標情報を使って正確に抽出する方法です。
表データ抽出のコード
def extract_table_with_coordinates(pdf_path):
with pdfplumber.open(pdf_path) as pdf:
page = pdf.pages[0]
# 表を自動検出
tables = page.extract_tables()
if tables:
table = tables[0] # 最初の表を処理
print("表データと座標情報:")
for row_index, row in enumerate(table):
for col_index, cell in enumerate(row):
if cell: # セルが空でない場合
# セルの座標を推定(簡易版)
print(f"行{row_index}, 列{col_index}: '{cell}'")
# より詳細な座標情報が必要な場合
table_settings = {
"vertical_strategy": "lines",
"horizontal_strategy": "lines"
}
detailed_table = page.extract_table(table_settings)
return detailed_table
return None
# 使用例
table_data = extract_table_with_coordinates('table_document.pdf')
座標変換とページ座標系の対応
異なる座標系への変換
PDF座標をピクセル座標や他の単位系に変換する方法です。
座標変換のコード例
def convert_coordinates(pdf_coords, page_height, dpi=72):
"""
PDF座標を画面座標に変換
PDFは左下が原点、画面は左上が原点
"""
x_pdf, y_pdf = pdf_coords
# Y座標を反転(左下原点 → 左上原点)
y_screen = page_height - y_pdf
# DPI変換(必要に応じて)
if dpi != 72: # 72 DPIがPDFの標準
scale_factor = dpi / 72
x_screen = x_pdf * scale_factor
y_screen = y_screen * scale_factor
else:
x_screen = x_pdf
return x_screen, y_screen
# 使用例
pdf_x, pdf_y = 100, 200
page_height = 842 # A4の高さ
screen_x, screen_y = convert_coordinates((pdf_x, pdf_y), page_height)
print(f"PDF座標: ({pdf_x}, {pdf_y}) → 画面座標: ({screen_x}, {screen_y})")
ページ回転への対応
回転されたPDFページでの座標補正方法です。
回転補正のコード
import math
def adjust_for_rotation(x, y, rotation, page_width, page_height):
"""
ページ回転に対応した座標補正
"""
if rotation == 0:
return x, y
elif rotation == 90:
return y, page_width - x
elif rotation == 180:
return page_width - x, page_height - y
elif rotation == 270:
return page_height - y, x
else:
# 任意角度の回転(ラジアンに変換)
rad = math.radians(rotation)
new_x = x * math.cos(rad) - y * math.sin(rad)
new_y = x * math.sin(rad) + y * math.cos(rad)
return new_x, new_y
# 使用例
original_x, original_y = 100, 200
rotation_angle = 90 # 90度回転
page_w, page_h = 595, 842
adjusted_x, adjusted_y = adjust_for_rotation(
original_x, original_y, rotation_angle, page_w, page_h
)
print(f"回転補正後の座標: ({adjusted_x}, {adjusted_y})")
エラー処理とデバッグ
よくあるエラーと対処法
PDF座標取得でよく発生する問題と解決方法をご紹介します。
エラー処理を含む実装例
def safe_coordinate_extraction(pdf_path):
try:
with pdfplumber.open(pdf_path) as pdf:
if len(pdf.pages) == 0:
raise ValueError("PDFにページが含まれていません")
page = pdf.pages[0]
# 座標取得処理
coordinates = []
for word in page.extract_words():
coordinates.append({
'text': word['text'],
'x0': word['x0'],
'y0': word['y0'],
'x1': word['x1'],
'y1': word['y1']
})
return coordinates
except FileNotFoundError:
print(f"ファイルが見つかりません: {pdf_path}")
return None
except Exception as e:
print(f"エラーが発生しました: {str(e)}")
return None
# 使用例
result = safe_coordinate_extraction('sample.pdf')
if result:
print(f"{len(result)}個の要素を取得しました")
デバッグ用の可視化
座標情報を視覚的に確認するためのコードです。
座標可視化のコード
import matplotlib.pyplot as plt
import matplotlib.patches as patches
def visualize_coordinates(pdf_path, output_image='coordinates.png'):
with pdfplumber.open(pdf_path) as pdf:
page = pdf.pages[0]
# 図を作成
fig, ax = plt.subplots(1, 1, figsize=(8, 11))
# ページサイズに合わせて軸を設定
ax.set_xlim(0, page.width)
ax.set_ylim(0, page.height)
ax.set_aspect('equal')
# テキストの座標を可視化
for word in page.extract_words():
x0, y0, x1, y1 = word['x0'], word['y0'], word['x1'], word['y1']
# バウンディングボックスを描画
rect = patches.Rectangle(
(x0, y0), x1-x0, y1-y0,
linewidth=1, edgecolor='red', facecolor='none'
)
ax.add_patch(rect)
# テキストを描画
ax.text(x0, y0, word['text'], fontsize=6, ha='left', va='bottom')
plt.title('PDF座標の可視化')
plt.xlabel('X座標')
plt.ylabel('Y座標')
plt.savefig(output_image, dpi=150, bbox_inches='tight')
plt.show()
# 使用例
visualize_coordinates('sample.pdf')
パフォーマンスの最適化
大容量PDFの効率的な処理
大きなPDFファイルを扱う際のパフォーマンス改善方法です。
最適化されたコード例
def optimized_coordinate_extraction(pdf_path, target_pages=None):
"""
メモリ効率を考慮した座標取得
"""
coordinates = []
with pdfplumber.open(pdf_path) as pdf:
pages_to_process = target_pages or range(len(pdf.pages))
for page_num in pages_to_process:
if page_num < len(pdf.pages):
page = pdf.pages[page_num]
# 必要な情報のみ抽出
page_coords = []
for word in page.extract_words():
# 座標のみを保存(メモリ節約)
page_coords.append((
word['text'],
round(word['x0'], 2),
round(word['y0'], 2),
round(word['x1'], 2),
round(word['y1'], 2)
))
coordinates.extend(page_coords)
# ガベージコレクションを促進
del page_coords
return coordinates
# 使用例(最初の5ページのみ処理)
coords = optimized_coordinate_extraction('large_document.pdf', target_pages=range(5))
まとめ
PythonによるPDF座標取得は、文書処理の自動化において非常に強力なツールです。
PyPDF2、pdfplumber、PyMuPDFなど、それぞれに特徴があるライブラリを使い分けることで、様々なニーズに対応できます。基本的な座標取得ならpdfplumberが最も使いやすく、高速処理が必要ならPyMuPDFがおすすめです。
重要なのは、PDF座標系の仕組みを理解し、適切なエラー処理を行うことです。また、実際の業務で使用する際は、パフォーマンスとメモリ使用量も考慮する必要があります。
これらの技術を活用して、請求書処理や文書解析の自動化など、あなたの業務をより効率的にしていきましょう!
コメント