はじめに
こんにちは、松延です。ZEN大学(通信制)の2年生で、AIエンジニアを目指して勉強しています。
Kaggleのノートブック(kernel)をローカルから kaggle kernels push で動かすようになってから、地味に時間を取られていたのが「今どうなっているかの確認」でした。実行中なのか、終わったのか、失敗したのか。失敗したならどこで落ちたのか。これを毎回ブラウザやログファイルで確認するのが面倒だったんです。
この記事では、Kaggle CLIの kaggle kernels status と kaggle kernels output を Python から呼び出して、状態とログを約7行のサマリー+CSV 1行にまとめるスクリプトを紹介します。あわせて、Windows で日本語が文字化けしたときの対策と、bat からでもAIエージェントからでも同じスクリプトを使えるようにするための工夫もまとめます。
なお、提出(submit)まわりの話ではなく、あくまで実行状況の監視とログの要約に絞った内容です。
以前のやり方
最初は、こんな bat ファイルで済ませていました。
@echo off
kaggle kernels status koheip/my-notebook
kaggle kernels output koheip/my-notebook -p .\out -o
notepad .\out\my-notebook.log
動くには動くのですが、困りごとがいくつかありました。
- ログが長く、メモ帳でスクロールしてエラー箇所を探すのが大変
- 日本語を含む出力がコンソール上で文字化けする
- 「いつ、どのノートブックが、どういう状態だったか」の記録が残らない
- AIエージェントにログ確認を頼むと、ログ全文を読ませることになり無駄が多い
特に最後の点が大きかったです。エージェントに渡すなら、必要な情報だけに絞った短いテキストのほうがずっと扱いやすいんですよね。
CLIで取る情報
使うコマンドは2つだけです(公式ドキュメント: Kaggle CLI Documentation、kaggle.com/docs/api)。
kaggle kernels status
最新の実行の状態を表示します。owner/kernel-slug の形式で指定します。
kaggle kernels status koheip/my-notebook
出力は次のような1行です(失敗時は Failure message: "..." の行が追加されます)。
koheip/my-notebook has status "KernelWorkerStatus.COMPLETE"
CLIのバージョンによって complete のような小文字表記だったり、KernelWorkerStatus. 付きだったりするので、スクリプト側では最後の単語だけ取り出して小文字にそろえるようにしています。
kaggle kernels output
最新の実行の出力ファイルをダウンロードします。主なオプションは次のとおりです。
| オプション | 意味 |
|---|---|
-p, --path |
保存先フォルダ |
-o, --force |
既存ファイルを上書き |
-q, --quiet |
進捗表示を抑える |
--file-pattern |
正規表現に一致するファイルだけ取得 |
ポイントは、出力ファイルと一緒に <kernel-slug>.log という実行ログも保存されることです。中身は多くの場合、stream_name(stdout / stderr)・time・data を持つ要素の JSON 配列になっています。今回はこのログを読んで要約します。
大きな出力ファイルがあるノートブックでは、--file-pattern で絞ると速くなります。
認証
Kaggle CLI は、環境変数 KAGGLE_API_TOKEN、~/.kaggle/access_token、従来の ~/.kaggle/kaggle.json などで認証できます。今回は「トークンを専用ファイルから読み、子プロセスにだけ環境変数として渡す」方式にしました。こうすると、bat から呼んでもエージェントから呼んでも、同じ読み込み経路になります。
要約スクリプト例
kaggle_status_summary.py として保存して使います。標準ライブラリのみで動きます。
# kaggle_status_summary.py
import argparse
import csv
import json
import os
import re
import subprocess
import sys
from datetime import datetime
from pathlib import Path
# Windowsでも標準出力をUTF-8に寄せる(Python 3.7+)
if hasattr(sys.stdout, "reconfigure"):
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
DEFAULT_TOKEN_FILE = Path.home() / ".config" / "kaggle_token.txt"
def build_env(token_file: Path) -> dict:
"""トークンをファイルから読み、子プロセス用の環境変数を作る"""
env = os.environ.copy()
env["PYTHONIOENCODING"] = "utf-8"
env["PYTHONUTF8"] = "1"
if token_file.exists():
env["KAGGLE_API_TOKEN"] = token_file.read_text(encoding="utf-8").strip()
return env
def run(cmd: list[str], env: dict) -> str:
r = subprocess.run(
cmd, env=env, capture_output=True,
text=True, encoding="utf-8", errors="replace",
)
if r.returncode != 0:
raise RuntimeError(f"{' '.join(cmd)} failed: {r.stderr.strip()[:300]}")
return r.stdout
def get_status(kernel: str, env: dict) -> tuple[str, str]:
out = run(["kaggle", "kernels", "status", kernel], env)
m = re.search(r'has status "([^"]+)"', out)
status = m.group(1).split(".")[-1].lower() if m else "unknown"
f = re.search(r'Failure message: "(.*)"', out)
return status, (f.group(1) if f else "")
def read_log(log_path: Path) -> list[tuple[str, str]]:
"""(stream_name, text) のリストにする。JSONでなければ素のテキストとして扱う"""
raw = log_path.read_text(encoding="utf-8", errors="replace")
try:
items = json.loads(raw)
return [(i.get("stream_name", ""), str(i.get("data", ""))) for i in items]
except (json.JSONDecodeError, AttributeError, TypeError):
return [("", line) for line in raw.splitlines()]
def main() -> int:
ap = argparse.ArgumentParser()
ap.add_argument("kernel", help="owner/kernel-slug")
ap.add_argument("--out", default="kaggle_out")
ap.add_argument("--csv", default="kaggle_status_log.csv")
ap.add_argument("--token-file", type=Path, default=DEFAULT_TOKEN_FILE)
args = ap.parse_args()
env = build_env(args.token_file)
status, failure = get_status(args.kernel, env)
slug = args.kernel.split("/")[1]
out_dir = Path(args.out) / slug
entries, files = [], []
if status in ("complete", "error", "cancelacknowledged"):
out_dir.mkdir(parents=True, exist_ok=True)
run(["kaggle", "kernels", "output", args.kernel,
"-p", str(out_dir), "-o", "-q"], env)
files = [p.name for p in out_dir.iterdir() if p.is_file()]
log_path = out_dir / f"{slug}.log"
if log_path.exists():
entries = read_log(log_path)
err_pat = re.compile(r"(Error|Exception|Traceback|エラー)")
stderr_n = sum(1 for s, _ in entries if s == "stderr")
err_lines = [t.strip() for _, t in entries if err_pat.search(t)]
last_line = next((t.strip() for _, t in reversed(entries) if t.strip()), "")
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
# ここが「約7行」のサマリー
print(f"[kernel] {args.kernel}")
print(f"[checked] {now}")
print(f"[status] {status}" + (f" / {failure}" if failure else ""))
print(f"[log] {len(entries)} entries (stderr: {stderr_n})")
print(f"[errors] {len(err_lines)} lines")
print(f"[last_err] {err_lines[-1][:120] if err_lines else '-'}")
print(f"[tail] {last_line[:120] or '-'} / files: {len(files)}")
# 履歴としてCSVに1行追記(Excelで開けるようにBOM付き)
csv_path = Path(args.csv)
new = not csv_path.exists()
with csv_path.open("a", newline="", encoding="utf-8-sig") as f:
w = csv.writer(f)
if new:
w.writerow(["checked_at", "kernel", "status", "log_entries",
"stderr", "error_lines", "last_error", "files"])
w.writerow([now, args.kernel, status, len(entries), stderr_n,
len(err_lines), err_lines[-1][:200] if err_lines else "",
len(files)])
return 0 if status != "error" else 1
if __name__ == "__main__":
sys.exit(main())
実行するとこんな感じになります(値は例です)。
[kernel] koheip/my-notebook
[checked] 2026-10-31 15:42:10
[status] complete
[log] 214 entries (stderr: 12)
[errors] 0 lines
[last_err] -
[tail] 処理が完了しました / files: 3
工夫したところは次の3点です。
-
終了コード:
errorのときは 1 を返すので、bat のif errorlevel 1やエージェント側で分岐しやすい -
状態の正規化:CLIのバージョン差を吸収するため、
KernelWorkerStatus.COMPLETE→completeのようにそろえる -
実行中はダウンロードしない:
running/queuedのときは status だけ見て終わるので、短い間隔で呼んでも軽い
ただし、Kaggle の API にはレート制限があります。ループで監視する場合は、数分おきなど間隔を空けるようにしましょう。
トークンファイルの置き方
トークンは Kaggleの設定ページ で発行し、1行だけのテキストファイルとして保存します。
# PowerShell:トークンファイルを作成(中身はトークン1行だけ)
New-Item -ItemType Directory -Force "$HOME\.config" | Out-Null
Set-Content -Path "$HOME\.config\kaggle_token.txt" -Value "ここにトークン" -Encoding ascii -NoNewline
このファイルは Git 管理下に置かない、記事やチャットに貼らない、の2点は徹底しています。エージェントから使うときも、渡すのは「スクリプトのパス」だけで、トークンそのものは見せずに済みます。
Windowsの文字化け対策
Windows の日本語環境では、コンソールのコードページが既定で CP932(Shift_JIS)です。一方、Kaggle のログは UTF-8 なので、何もしないと日本語が化けたり、UnicodeEncodeError で止まったりします。
対策は「コンソール側」と「Python側」の両方で UTF-8 にそろえることです。
bat から呼ぶ場合
@echo off
chcp 65001 >nul
set PYTHONIOENCODING=utf-8
set PYTHONUTF8=1
python "%~dp0kaggle_status_summary.py" koheip/my-notebook
if errorlevel 1 echo [!] 実行がエラーで終わっています
bat ファイル自体に日本語を書く場合は、ファイルを UTF-8 で保存しておくと chcp 65001 後に正しく表示されます。
PowerShell から呼ぶ場合
chcp 65001 > $null
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$OutputEncoding = [System.Text.Encoding]::UTF8
$env:PYTHONIOENCODING = "utf-8"
$env:PYTHONUTF8 = "1"
python .\kaggle_status_summary.py koheip/my-notebook
if ($LASTEXITCODE -ne 0) { Write-Host "[!] 実行がエラーで終わっています" }
Python 側でやっていること
スクリプト内でも念のため次の3つをしています。
-
sys.stdout.reconfigure(encoding="utf-8")で標準出力を UTF-8 に -
subprocess.run(..., encoding="utf-8", errors="replace")で子プロセスの出力を UTF-8 として読む - 子プロセス(kaggle CLI)の環境変数にも
PYTHONIOENCODING=utf-8を渡す
chcp 65001 だけ、PYTHONIOENCODING だけでは片方しか直らないケースがあり、私も最初はハマりました。両方そろえるのがコツです。
まとめ
-
kaggle kernels statusで状態、kaggle kernels outputで出力と<slug>.logを取得できる - Python でログを読み、約7行のサマリー+CSV 1行にまとめると、確認がぐっと楽になる
- トークンはファイルから読み込んで子プロセスに渡すと、bat からもエージェントからも同じ経路で使える
- Windows では
chcp 65001とPYTHONIOENCODING=utf-8の両方で文字化けを防ぐ
メモ帳でログをスクロールしていたころに比べて、確認にかかる時間も、エージェントに渡す情報量も大きく減りました。同じように Kaggle のノートブックをローカルから回している方の参考になればうれしいです。