QGISバッチ処理入門

同じ処理を複数のファイルに適用したいとき、バッチ処理が便利です。

QGISバッチ処理入門【複数ファイルの一括処理】

この記事では、QGISでバッチ処理を行う方法を解説します。

バッチ処理とは

概要

バッチ処理 = 複数のデータに同じ処理を一括で適用すること

【手動処理】
ファイル1 → 処理 → 出力1
ファイル2 → 処理 → 出力2
ファイル3 → 処理 → 出力3
→ 時間がかかる、ミスが起きやすい

【バッチ処理】
[ファイル1, 2, 3] → 一括処理 → [出力1, 2, 3]
→ 効率的、確実

活用シーン

シーン 処理内容
座標系変換 複数ファイルをまとめて変換
バッファ作成 複数レイヤにバッファを作成
形式変換 シェープファイル→GeoPackage
属性計算 全ファイルの面積を計算

処理ツールのバッチ実行

バッチ処理の起動

手順

  • プロセシング → ツールボックス
  • 使いたいツールを右クリック
  • 「バッチ処理として実行」

バッチ処理画面

┌────────────────────────────────────────────┐
│  パラメータ1  パラメータ2  出力         │
├────────────────────────────────────────────┤
│  入力1       100         出力1.shp     │
│  入力2       100         出力2.shp     │
│  入力3       100         出力3.shp     │
├────────────────────────────────────────────┤
│  [行を追加] [自動入力] [実行]            │
└────────────────────────────────────────────┘

入力ファイルの一括追加

手順

  • 「入力」列のセルをダブルクリック
  • ファイル選択ダイアログ
  • 複数ファイルを選択(Ctrl+クリック)
  • 各行に自動で展開される

出力ファイル名の自動生成

出力列で「自動入力」を使用:
・入力ファイル名をベースに自動生成
・接頭辞/接尾辞を追加可能

例:
入力:data.shp
出力:data_buffered.shp

PyQGISでのバッチ処理

基本パターン

python
import os
import processing

input_folder = "C:/data/input"
output_folder = "C:/data/output"

# フォルダ内のシェープファイルを処理
for filename in os.listdir(input_folder):
    if filename.endswith(".shp"):
        input_path = os.path.join(input_folder, filename)
        output_name = filename.replace(".shp", "_processed.shp")
        output_path = os.path.join(output_folder, output_name)

        # 処理を実行
        processing.run("native:buffer", {
            'INPUT': input_path,
            'DISTANCE': 100,
            'OUTPUT': output_path
        })

        print(f"処理完了: {filename}")

print("すべての処理が完了しました")

複数の処理を連続実行

python
def process_file(input_path, output_folder):
    filename = os.path.basename(input_path)
    name = os.path.splitext(filename)[0]

    # 処理1: 座標系変換
    reprojected = processing.run("native:reprojectlayer", {
        'INPUT': input_path,
        'TARGET_CRS': 'EPSG:6677',
        'OUTPUT': 'memory:'
    })['OUTPUT']

    # 処理2: バッファ
    buffered = processing.run("native:buffer", {
        'INPUT': reprojected,
        'DISTANCE': 50,
        'OUTPUT': 'memory:'
    })['OUTPUT']

    # 処理3: 出力
    output_path = os.path.join(output_folder, f"{name}_result.gpkg")
    processing.run("native:savefeatures", {
        'INPUT': buffered,
        'OUTPUT': output_path
    })

    return output_path

# バッチ実行
for filepath in glob.glob("C:/data/*.shp"):
    result = process_file(filepath, "C:/output")
    print(f"完了: {result}")

実践的なバッチ処理例

例1: 座標系一括変換

python
import os
import processing

def batch_reproject(input_folder, output_folder, target_crs):
    """複数ファイルの座標系を一括変換"""
    os.makedirs(output_folder, exist_ok=True)

    for filename in os.listdir(input_folder):
        if filename.endswith(('.shp', '.gpkg', '.geojson')):
            input_path = os.path.join(input_folder, filename)
            output_path = os.path.join(output_folder, filename)

            try:
                processing.run("native:reprojectlayer", {
                    'INPUT': input_path,
                    'TARGET_CRS': target_crs,
                    'OUTPUT': output_path
                })
                print(f"✓ {filename}")
            except Exception as e:
                print(f"✗ {filename}: {e}")

# 実行
batch_reproject(
    "C:/data/input",
    "C:/data/output_epsg6677",
    "EPSG:6677"
)

例2: シェープファイル→GeoPackage変換

python
import os
import processing

def shp_to_gpkg(input_folder, output_gpkg):
    """複数シェープファイルを1つのGeoPackageに統合"""

    for filename in os.listdir(input_folder):
        if filename.endswith(".shp"):
            input_path = os.path.join(input_folder, filename)
            layer_name = os.path.splitext(filename)[0]

            options = QgsVectorFileWriter.SaveVectorOptions()
            options.actionOnExistingFile = QgsVectorFileWriter.CreateOrOverwriteLayer
            options.layerName = layer_name

            layer = QgsVectorLayer(input_path, layer_name, "ogr")

            QgsVectorFileWriter.writeAsVectorFormatV3(
                layer,
                output_gpkg,
                QgsCoordinateTransformContext(),
                options
            )
            print(f"追加: {layer_name}")

# 実行
shp_to_gpkg("C:/data/shapefiles", "C:/data/combined.gpkg")

例3: 面積・長さの一括計算

python
import os

def calculate_geometry_batch(input_folder, field_name, calc_type):
    """複数ファイルのジオメトリを計算して属性に追加"""

    for filename in os.listdir(input_folder):
        if filename.endswith(".gpkg"):
            filepath = os.path.join(input_folder, filename)
            layer = QgsVectorLayer(filepath, filename, "ogr")

            if not layer.isValid():
                continue

            # フィールド追加
            layer.startEditing()
            if field_name not in [f.name() for f in layer.fields()]:
                layer.addAttribute(QgsField(field_name, QVariant.Double))
                layer.updateFields()

            field_index = layer.fields().indexOf(field_name)

            # 計算
            for feature in layer.getFeatures():
                if calc_type == "area":
                    value = feature.geometry().area()
                elif calc_type == "length":
                    value = feature.geometry().length()
                else:
                    value = 0

                layer.changeAttributeValue(feature.id(), field_index, value)

            layer.commitChanges()
            print(f"計算完了: {filename}")

# 実行(面積計算)
calculate_geometry_batch("C:/data", "calc_area", "area")

エラーハンドリング

基本的なエラー処理

python
import traceback

def safe_batch_process(input_folder, output_folder):
    """エラーが発生しても処理を継続"""
    success = []
    failed = []

    for filename in os.listdir(input_folder):
        if filename.endswith(".shp"):
            input_path = os.path.join(input_folder, filename)
            output_path = os.path.join(output_folder, filename)

            try:
                processing.run("native:buffer", {
                    'INPUT': input_path,
                    'DISTANCE': 100,
                    'OUTPUT': output_path
                })
                success.append(filename)
            except Exception as e:
                failed.append({
                    'file': filename,
                    'error': str(e),
                    'traceback': traceback.format_exc()
                })

    # 結果サマリ
    print(f"\n=== 処理結果 ===")
    print(f"成功: {len(success)}件")
    print(f"失敗: {len(failed)}件")

    if failed:
        print("\n失敗したファイル:")
        for f in failed:
            print(f"  - {f['file']}: {f['error']}")

    return success, failed

入力検証

python
def validate_input(filepath):
    """入力ファイルの検証"""
    if not os.path.exists(filepath):
        raise FileNotFoundError(f"ファイルが見つかりません: {filepath}")

    layer = QgsVectorLayer(filepath, "test", "ogr")
    if not layer.isValid():
        raise ValueError(f"無効なレイヤ: {filepath}")

    if layer.featureCount() == 0:
        raise ValueError(f"フィーチャがありません: {filepath}")

    return True

ログと進捗管理

ログファイルの出力

python
import logging
from datetime import datetime

def setup_logging(log_folder):
    """ログ設定"""
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    log_file = os.path.join(log_folder, f"batch_{timestamp}.log")

    logging.basicConfig(
        filename=log_file,
        level=logging.INFO,
        format='%(asctime)s - %(levelname)s - %(message)s'
    )

    return logging.getLogger()

# 使用例
logger = setup_logging("C:/logs")
logger.info("バッチ処理開始")
logger.info(f"処理完了: {filename}")
logger.error(f"エラー: {error}")

プログレス表示

python
def batch_with_progress(input_files, output_folder):
    """プログレス付きバッチ処理"""
    total = len(input_files)

    for i, filepath in enumerate(input_files):
        progress = (i + 1) / total * 100
        print(f"\r処理中: {progress:.1f}% ({i+1}/{total})", end="")

        # 処理
        process_file(filepath, output_folder)

    print("\n完了!")

まとめ

バッチ処理のポイント

ポイント

  • 処理ツールの「バッチ処理として実行」が簡単
  • 複雑な処理はPyQGISで
  • エラーハンドリングを忘れずに
  • ログを残して追跡可能に

チェックリスト

実行前の確認

  • 入力ファイルの形式・座標系を確認
  • 出力先フォルダを準備
  • テストデータで動作確認
  • エラー処理を実装
  • ログを記録

関連記事

お問い合わせ

バッチ処理の自動化についてのご相談は、お気軽にお問い合わせください。

  • 自動化相談
  • スクリプト開発支援
  • 業務効率化コンサルティング

お問い合わせはこちら

最終更新: 2025年1月