【Python】argparseでJSON整形・構文検証・キー検索CLIを試してみた

【Python】argparseでJSON整形・構文検証・キー検索CLIを試してみた

公開: 更新:
CodeCampが提供するDX人材育成が可能なプログラミングやITが学べる公開講座

JSONを整形して眺めたり、構文が壊れていないか確認したり、ネストの奥にあるキーを探したり――そんな地味だけど頻発する作業を、Pythonのargparseだけで賄うCLIツールを実際に作りました。formatvalidatesearchの3コマンドに分けたことで、用途ごとに迷わず使える仕上がりになりました。

【Python】argparseでJSON整形・構文検証・キー検索CLIを試してみた|概要動画
動画の内容をテキストで確認する

オープニング。argparseを使った実践内容を約34秒で紹介します。概要紹介。

この動画では、argparseでJSON整形・構文検証・キー検索CLIを作ります。具体的にやること。具体的には、3つのサブコマンドを分け、ネストしたキーを再帰検索します。

実装環境・必須アプリ。実装環境と必須アプリは、Windows 11 Pro / Python 3.13.3 / argparseです。実際のキャプチャ動画。

実際の画面で操作を確認します。検証の結果、CLIツールを4回のコマンドで実行し、全て正常(終了コード0)に動作しました。エンディング。

研修ならCodeCampで検索。

Pythonでargparseのコードを生成したプロンプトと作り方

処理を3つのサブコマンドへ分けることで、入力方法と責務を明確にしています。JSON本文を直接渡す指定にすると、追加ファイルなしで同じ実行例を再現できます。

構文検証とキー検索の意味を分け、検索条件をキー名の完全一致に限定しました。再帰対象に辞書と配列の両方を明記することで、ネストしたJSONでも検索漏れを防ぎます。

生成プロンプトで工夫したポイント

  • サブコマンドはformat、validate、searchの3つにします。:この指定により、完成物の機能範囲と各処理の責務が明確になります。
  • 任意の--strict時だけ不正JSONを終了コード1にしてください。:画面での検査と自動処理向けの終了コードを両立できる点が利点です。
  • dictとlistの全階層から再帰的に完全一致検索:ネスト構造と検索条件を具体化し、値検索との混同を防げます。

同じコードを作れる生成プロンプト(コピペ用・全文)

実際の生成時には、この記事のシステム都合の指定(図の保存先など)を少しだけ足していますが、以下はそのままコピペして同じものが作れるように整えた全文です。

Python標準ライブラリのargparseとjsonを使い、JSON本文を--jsonで受け取るCLIを作ってください。サブコマンドはformat、validate、searchの3つにします。formatはインデント付きJSONを表示し、validateは構文の成否と行・列を表示して、任意の--strict時だけ不正JSONを終了コード1にしてください。searchは--keyで指定したキー名をdictとlistの全階層から再帰的に完全一致検索し、JSONPath風の位置と値を表示してください。main関数と直接実行用ガードを付けてください。
さらに詳しく学べるPython研修の詳細はこちら

Python・argparseの環境構築(Windows 11/PowerShellで検証)

この記事のセットアップ手順と掲載コードは、Windows 11 Pro、PowerShell 5.1、Python 3.13.3で動作確認しています。仮想環境を有効化せず、その中のPythonを直接指定するため、以下のコマンドはPowerShellとコマンドプロンプト(cmd)の両方で使えます。

python -m venv .venv

macOS・Linuxでは仮想環境内のPythonパスが異なります。今回の動作確認環境とは異なるため、以下は環境差分を補う参考手順です。

python3 -m venv .venv
  • 追加パッケージは不要で、Python標準ライブラリだけで動作します。
さらに詳しく学べるPython研修の詳細はこちら

Pythonのargparseで作るJSON CLIの方針

この記事では、Pythonのargparseを使ってJSONを整形・検証・キー検索できるコマンドラインツールを実際に作ります。

方針はシンプルで、formatvalidatesearchという3つの処理をargparseのサブパーサーで分離し、それぞれ独立したコマンドとして扱うことにしました。

入力されたJSON文字列はjson.loadsで解析し、キー検索だけは辞書とリストをたどる再帰関数にまとめて、見つかった位置をJSONPath風の表記で表示する設計にしています。

このセクションの用語

サブパーサー
1つのCLIの中にformatsearchのような複数のサブコマンドを定義するためのargparseの仕組みです。
JSONPath風表記
$.user.nameのように、JSON内のどの位置にある値かを.[]で示す簡易的な表記方法です。
argparseのサブパーサーからJSON処理までの流れ CLI起動時にコマンド名を受け取るargparseがformat/validate/searchを判定json.loadsでJSON文字列を解析各サブコマンドの処理関数を実行結果またはINVALIDを標準出力に表示
argparseのサブパーサーからJSON処理までの流れ

参考:

©Python公式ドキュメント(argparse)

argparse supports the creation of such sub-commands with the add_subparsers() method.


Python研修一覧はこちら

目的に合うPython研修を一覧形式から探したい方は、ぜひご利用ください。

Python研修を比較する

Java研修一覧はこちら

目的に合うJava研修を一覧形式から探したい方は、ぜひご利用ください。

Java研修を比較する

PHP研修一覧はこちら

目的に合うPHP研修を一覧形式から探したい方は、ぜひご利用ください。

PHP研修を比較する

新入社員研修

目的に合う新入社員研修を一覧形式から探したい方は、ぜひご利用ください。

新入社員研修を比較する

全ての研修からも探したい方はこちら

Pythonでjson.loadsとargparseで実装するJSON整形・検証・キー検索

実装は4つの処理を素直に関数へ分けただけのシンプルな構成です。command_formatcommand_validatecommand_searchという3つのハンドラ関数と、キー検索用のfind_key関数を用意しました。

各ハンドラはargs.jsonjson.loadsで解析し、失敗するとjson.JSONDecodeErrorを捕まえてエラー内容と行・列番号を表示します。

最後にbuild_parser関数がargparse.ArgumentParseradd_subparsersでコマンドラインの入り口を組み立てる役割です。

このセクションの用語

JSONDecodeError
json.loadsに渡した文字列がJSONとして不正な形式だったときにPythonが送出する例外です。
再帰関数
自分自身を呼び出しながら、ネストした辞書やリストの奥まで処理を繰り返す関数のことです。
searchサブコマンド実行時のデータの流れ --jsonの文字列を受け取るjson.loadsでPythonオブジェクト化dict/listを再帰的に探索JSONPath風パスとマッチ値を出力
searchサブコマンド実行時のデータの流れ
# -*- coding: utf-8 -*-
"""JSON整形・構文検証・キー検索だけを扱うargparse製CLI。"""
from __future__ import annotations

import argparse
import json
from typing import Any


# JSONの整形
def command_format(args: argparse.Namespace) -> int:
    try:
        data = json.loads(args.json)
    except json.JSONDecodeError as exc:
        print(f"INVALID: {exc.msg} (line {exc.lineno}, column {exc.colno})")
        return 1
    print(json.dumps(data, ensure_ascii=False, indent=2, sort_keys=True))
    return 0


# JSON構文の検証
def command_validate(args: argparse.Namespace) -> int:
    try:
        json.loads(args.json)
    except json.JSONDecodeError as exc:
        print(f"INVALID: {exc.msg} (line {exc.lineno}, column {exc.colno})")
        return 1 if args.strict else 0
    print("VALID: JSON構文に問題はありません。")
    return 0


# ネストしたキーの再帰検索
def find_key(node: Any, target_key: str, path: str = "$") -> list[tuple[str, Any]]:
    matches: list[tuple[str, Any]] = []
    if isinstance(node, dict):
        for key, value in node.items():
            child_path = f"{path}.{key}"
            if key == target_key:
                matches.append((child_path, value))
            matches.extend(find_key(value, target_key, child_path))
    elif isinstance(node, list):
        for index, value in enumerate(node):
            matches.extend(find_key(value, target_key, f"{path}[{index}]"))
    return matches


def command_search(args: argparse.Namespace) -> int:
    try:
        data = json.loads(args.json)
    except json.JSONDecodeError as exc:
        print(f"INVALID: {exc.msg} (line {exc.lineno}, column {exc.colno})")
        return 1
    matches = find_key(data, args.key)
    print(f"FOUND: {len(matches)}件")
    for path, value in matches:
        rendered = json.dumps(value, ensure_ascii=False, separators=(",", ":"))
        print(f"{path} = {rendered}")
    return 0


# argparseのサブコマンド定義
def build_parser() -> argparse.ArgumentParser:
    parser = argparse.ArgumentParser(
        description="JSONの整形・構文検証・キー検索を行うCLIです。")
    subcommands = parser.add_subparsers(dest="command", required=True)

    format_parser = subcommands.add_parser("format", help="JSONを読みやすく整形します。")
    format_parser.add_argument("--json", required=True, help="整形するJSON本文")
    format_parser.set_defaults(handler=command_format)

    validate_parser = subcommands.add_parser("validate", help="JSON構文を検証します。")
    validate_parser.add_argument("--json", required=True, help="検証するJSON本文")
    validate_parser.add_argument(
        "--strict", action="store_true",
        help="INVALIDの場合に終了コード1を返します。")
    validate_parser.set_defaults(handler=command_validate)

    search_parser = subcommands.add_parser("search", help="キー名を再帰検索します。")
    search_parser.add_argument("--json", required=True, help="検索するJSON本文")
    search_parser.add_argument("--key", required=True, help="完全一致で探すキー名")
    search_parser.set_defaults(handler=command_search)
    return parser


def main() -> int:
    args = build_parser().parse_args()
    return int(args.handler(args))


if __name__ == "__main__":
    raise SystemExit(main())

コード全文は上の折り畳みに入れてあるので、全部を上から読む必要はありません。ここでは特に重要な部分だけを抜き出して、何をしているのか順番に見ていきます。

command_format関数でJSONを整形する

def command_format(args: argparse.Namespace) -> int:
    try:
        data = json.loads(args.json)
    except json.JSONDecodeError as exc:
        print(f"INVALID: {exc.msg} (line {exc.lineno}, column {exc.colno})")
        return 1
    print(json.dumps(data, ensure_ascii=False, indent=2, sort_keys=True))
    return 0

--jsonで渡された文字列をjson.loadsでPythonのオブジェクトに変換し、json.dumpsでインデント付き・キーのソート済みの読みやすい形式に整形します。解析に失敗した場合は、終了コード1を返す仕様です。

json.JSONDecodeErrorで構文エラーを捕捉する

    except json.JSONDecodeError as exc:
        print(f"INVALID: {exc.msg} (line {exc.lineno}, column {exc.colno})")
        return 1

3つのハンドラすべてで同じパターンを使い、exc.msgexc.linenoexc.colnoからエラーメッセージと発生位置を表示する仕組みです。どこが壊れているJSONなのか特定しやすくなります。

command_validate関数と--strictオプション

def command_validate(args: argparse.Namespace) -> int:
    try:
        json.loads(args.json)
    except json.JSONDecodeError as exc:
        print(f"INVALID: {exc.msg} (line {exc.lineno}, column {exc.colno})")
        return 1 if args.strict else 0
    print("VALID: JSON構文に問題はありません。")
    return 0

構文検証だけを行うコマンドです。--strictが指定されていれば不正なJSONのときに終了コード1を返し、指定がなければ0のままメッセージだけ表示するという挙動の切り替えができます。

find_key関数でネストしたキーを再帰的にたどる

def find_key(node: Any, target_key: str, path: str = "$") -> list[tuple[str, Any]]:
    matches: list[tuple[str, Any]] = []
    if isinstance(node, dict):
        for key, value in node.items():
            child_path = f"{path}.{key}"
            if key == target_key:
                matches.append((child_path, value))
            matches.extend(find_key(value, target_key, child_path))

辞書ならキーと値を1つずつ確認し、目的のキーと一致すれば現在位置を記録します。値がさらに辞書やリストであればfind_key自身を再度呼び出し、ネストの奥まで探索を続ける仕組みです。

リスト要素をたどるインデックス付きパス

    elif isinstance(node, list):
        for index, value in enumerate(node):
            matches.extend(find_key(value, target_key, f"{path}[{index}]"))
    return matches

対象がリストの場合はenumerateで要素番号を取り出し、[0]のようにインデックス付きのパス文字列を組み立てながら再帰します。この処理によって、リスト内の辞書にもキー検索が届くようになりました。

build_parserとサブパーサーでコマンドを分離

    subcommands = parser.add_subparsers(dest="command", required=True)

    format_parser = subcommands.add_parser("format", help="JSONを読みやすく整形します。")
    format_parser.add_argument("--json", required=True, help="整形するJSON本文")
    format_parser.set_defaults(handler=command_format)

add_subparsersformatvalidatesearchのサブコマンドを追加し、それぞれに--json引数と対応するハンドラ関数をset_defaultsで紐づけます。コマンド名ごとに処理が完全に分かれるのがこの設計の利点です。


Python基礎・実践(Django)

企業・法人向けのPython研修では、基礎から応用まで体系的に学べます。

Python研修の詳細

DX社員研修

企業・法人向けのDX研修では、実務に繋がるリスキリングでITレベルを向上させます。

DX研修の詳細

Javaエンジニア育成研修

企業・法人向けのJavaエンジニア育成研修では、Javaの基礎から応用まで確実に習得できます。

Java研修の詳細

新卒・新入社員向け研修

企業・法人に新入社員・新卒社員に向けたプログラミング研修を提供しています。

新入社員研修の詳細

コードキャンプのIT研修を全て見る

Pythonで実行してみたJSON整形・検索CLIの結果

実際にこのCLIツールをコマンドラインから4回実行し、formatvalidatesearchそれぞれの動作を確認しました。

4回の実行はすべて正常に完了し、終了コードは全て0でした。エラーメッセージが出るケースも試しましたが、想定通りINVALID表示と対応する終了コードが返ってきました。

画像として、実際にコマンドを打ち込んで結果が表示されるまでの実行セッションのキャプチャを残しています。

このセクションの用語

終了コード
コマンドの実行結果を表す数値で、0は正常終了、1などの非ゼロ値は何らかのエラーがあったことを示します。
CLIツールの実行セッション(実出力)
CLIツールの実行セッション(実出力)
さらに詳しく学べるPython研修の詳細はこちら

Python argparse CLIでよくあるJSONエラーと対処

argparseを使ったCLIツールでは、JSON自体の構文ミスとコマンドライン引数の指定ミスの両方でエラーが起きやすくなります。

代表的なパターンを事前に知っておくと、実行時に慌てずに対処できます。

エラー例 原因 対処
INVALID: Expecting value (line 1, column 1) --jsonに空文字や壊れたJSONを渡した JSON文字列全体をクォートで囲み、構文が閉じているか再確認する
error: the following arguments are required: --json --jsonオプションを付け忘れた コマンドに--json '...'の形で本文を追加する
error: argument command: invalid choice format/validate/searchのスペルミスや未定義のサブコマンド指定 -hオプションでサブコマンド名の一覧を確認する
シェル側でJSONの引用符が崩れて解析に失敗する PowerShellやbashでJSON文字列のクォートの扱いを誤った JSON全体をシングルクォートで囲むか、ファイルから読み込む方式に変える
FOUND: 0件と表示される 検索したいキー名のタイプミスやネスト構造の勘違い 先にformatで整形結果を確認してからキー名を見直す
さらに詳しく学べるPython研修の詳細はこちら

Pythonの再帰検索で初心者がつまずきやすいポイント

find_keyのような再帰関数は、一度理解してしまえば単純な処理ですが、最初はどこで止まるのか掴みにくいところです。

POINT

find_keyは辞書でもリストでもない値(文字列や数値)に到達すると何もせずmatchesを返すだけなので、無限に再帰し続ける心配はありません。

検索対象のキー名は完全一致でしか見つからないため、大文字・小文字の違いやタイプミスがあるとFOUND: 0件になります。原因を調べるには、formatで構造を確認するのが近道です。

同じキー名がJSON内に複数存在する場合、find_keyは最初の1件だけでなく見つかったすべての位置を返します。件数が多いときは出力が長くなる点に注意してください。

PowerShellやbashでJSON文字列を--jsonに渡すときは、引用符の扱いを誤るとシェル側でJSONが崩れてしまいます。JSON全体を1つの文字列としてクォートで囲むことを意識してください。

さらに詳しく学べるPython研修の詳細はこちら

JSONPath風キー検索が使える場面

searchサブコマンドはキー名を指定するだけで、ネストの深さに関係なく該当箇所を洗い出せるため、実務のちょっとした調査に応用しやすい機能です。

使える場面 具体的な使い方
APIレスポンスの目視確認 curlなどで取得したJSONをformatサブコマンドに渡し、インデント付きで読みやすく整形してから中身を確認する
設定ファイルの構文チェック デプロイ前にvalidateサブコマンドをスクリプトへ組み込み、--strict付きでJSON構文が壊れていないか自動チェックする
大きくネストしたJSONからの値抽出 設定ファイルや複雑なレスポンスに対してsearchサブコマンドでキー名を指定し、該当箇所をJSONPath風の位置情報付きで洗い出す
さらに詳しく学べるPython研修の詳細はこちら

Pythonで作るJSON CLIツールのまとめ

argparseのサブパーサーでformatvalidatesearchを分離し、json.loadsと再帰関数のfind_keyを組み合わせるだけで、実用的なJSON操作CLIを作れることを確認しました。

4回の実行はいずれも終了コード0で完了しており、整形・構文検証・キー検索の基本機能がひと通り動作します。

エラー位置や検索結果のパスも確認できるため、JSON処理の仕組みを理解しやすい題材です。

さらに詳しく学べるPython研修の詳細はこちら

参考にした一次情報

  1. ^ argparse — Parser for command-line options, arguments and sub-commands. https://docs.python.org/3/library/argparse.html, (参照26-07-15).
  2. ^ json — JSON encoder and decoder. https://docs.python.org/3/library/json.html, (参照26-07-15).

※内容は執筆時点のものです。ライブラリやサイトの仕様は変わる可能性があるため、公式ドキュメントもあわせてご確認ください。

ITやプログラミングに関するコラム


ITやプログラミングに関するニュース

ブログに戻る

コメントを残す

コメントは公開前に承認される必要があることにご注意ください。

企業・法人向けのIT・プログラミング・生成AI研修を探す、比較する - IT・プログラミングを知って学べるコネクトメディア CodeCampが提供するDX人材育成が可能なプログラミングやITが学べる公開講座 - IT・プログラミングを知って学べるコネクトメディア コードキャンプが提供する無料で学べるプログラミングスクール講座 - IT・プログラミングを知って学べるコネクトメディア コードキャンプDX人材育成研修 - IT・プログラミングを知って学べるコネクトメディア 3.5日の研修で、年間1,600時間の削減効果が見込まれる。東京きらぼしフィナンシャルグループのDX人材育成事例 - IT・プログラミングを知って学べるコネクトメディア 配属3ヶ月で30%の生産性向上を実現するいよぎんコンピュータサービスの新人研修に迫る - IT・プログラミングを知って学べるコネクトメディア 金融業界の業務効率化を加速するニッセイアセットマネジメントの生成AI×GAS活用研修事例 - IT・プログラミングを知って学べるコネクトメディア 【製造業のDX人材育成事例】デジタル人材の即戦力化を実現する、日本ガイシ株式会社の異動者向オンボーディング研修 - ITやプログラミングを知って学べるコネクトメディア フューチャーアーキテクト株式会社が実現した新入社員向けIT研修プログラムでタスクフォース制度が主体的な学びと成長を生み出す - IT・プログラミングを知って学べるコネクトメディア コードキャンプDX人材育成研修 - IT・プログラミングを知って学べるコネクトメディア コードキャンプIT・プログラミング研修事例/【IT新入社員研修】オンラインとオフラインの最適バランスを実現したFutureOneの導入事例 - IT・プログラミングを知って学べるコネクトメディア コードキャンプIT・プログラミング研修事例/【新入社員研修】柔軟なハイブリッド型Java研修で実現した新卒20名の成長と成果|サークレイス株式会社 - ITやプログラミングを知って学べるコネクトメディア コードキャンプIT・プログラミング研修事例/現場により近いところにデジタルを根付かせるDX基礎講座研修|株式会社ブリヂストン - ITやプログラミングを知って学べるコネクトメディア コードキャンプIT・プログラミング研修事例/業務の効率化・DX推進に向けたIT人材育成への第一歩|株式会社カナエ - ITやプログラミングを知って学べるコネクトメディア 企業・法人向けのIT・プログラミング研修 - ITやプログラミングを知って学べるコネクトメディア

新着記事

対象者別で探す

子供(小学生・中学生・高校生)向け
プログラミング教室検索する

子供(小学生・中学生・高校生)がロボットやプログラミング言語を学ぶことができるオフラインからオンラインスクールを検索、比較することが可能です。

子供(小学生・中学生・高校生)
プログラミング教室検索する

ITやプログラムなどの
最新情報を検索する

日々、新しいITやプログラミング言語の情報が流れていきますが、特定の情報を時系列でニュースやコラムを確認することができます。

ITやプログラムなどの
最新情報を検索する