e-Gov公文書のZIPファイルを解凍して自動PDF化(Mac)
CATEGORIES SHELL SCRIPT

e-Govからメールで通知文書送達のお知らせが来てもそこには何も書いておらず。さらにはアプリを開くまでも面倒だが、電子送達をダウンロードしないといけない。しかもXML拡張子で見るのも一苦労。

そんな面倒作業を自動化。ZIPファイルをダウンロードしたら勝手に解凍させてXMLファイルをPDFにしてしてフォルダに格納させる。

概要

e-Govの公文書zipをダウンロードすると、数秒〜十数秒で G-GOV電子申請フォルダに格納され、公文書本体と送付状がPDF化される。

  1. e-Govで公文書zip(16桁の番号_14桁の日時.zip)をダウンロードする(Safariが自動解凍してもOK)
  2. Automatorのフォルダアクションが、ダウンロードフォルダへの追加を検知する
  3. egov2pdf.sh が、zipか解凍済みフォルダを保存先(~/Documents/〇〇/G-GOV電子申請/)へ移動し、zipならその場で解凍する
  4. XSL指定のあるXMLを xsltproc でHTMLに変換し、Google Chromeのヘッドレス印刷でPDFにする
  5. 結果を _egov2pdf_log.txt に記録する

格納後のフォルダ構成(例)

ファイル中身
(16桁)_(14桁).zip原本(電子署名付き)。消さない
(16桁)/(公文書名).pdf公文書本体のPDF
(16桁)/(18桁の数字).pdf送付状のPDF
〜.xml / 〜.xsl / 〜.csv元データ。HTMLは変換の中間ファイル

構成ファイルと場所

動かしている部品は4つ。すべてMac本体にだけ置いてある。

部品場所役割
スクリプト~/bin/egov2pdf.sh格納・解凍・PDF化の本体
フォルダアクションAutomatorで保存した「e-Gov公文書PDF化」(対象:ダウンロード)追加を検知してスクリプトを起動
ログG-GOV電子申請/_egov2pdf_log.txt格納・PDF作成・失敗の記録
権限システム設定 → プライバシーとセキュリティ → フルディスクアクセス(またはファイルとフォルダ)の Folder Actions Dispatcherフォルダアクションから「書類」を読み書きするために必要

使っているコマンドは、すべてMac標準かChrome。

  • ditto:zipの解凍(標準)
  • xsltproc:XML+XSL → HTML(標準、/usr/bin)
  • Google Chrome:HTML → PDF(/Applications/Google Chrome.app)

スクリプト全文(~/bin/egov2pdf.sh)

対象は名前が「16桁_14桁」のzipとフォルダだけ。PDFが作成済みのXMLはスキップするので、何回実行しても重複しない。

#!/bin/zsh
# e-Gov公文書(zip/Safari自動解凍フォルダ)→ G-GOV電子申請フォルダへ格納 → XML+XSLをPDF化
SRC="$HOME/Downloads"
DEST="$HOME/Documents/〇〇/G-GOV電子申請"   # ← 自分の保存先に書き換える
CHROME="/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
LOG="$DEST/_egov2pdf_log.txt"
[[ -d "$DEST" ]] || { echo "保存先がありません: $DEST"; exit 1; }

log() { echo "$(date '+%Y-%m-%d %H:%M:%S') $1" >> "$LOG"; }

# 1. ダウンロード内の「16桁_14桁.zip」→ 保存先へ移動して、その場で解凍(「zip+16桁フォルダ」の並び)
#    Safariが自動解凍した「16桁_14桁」フォルダ → そのまま保存先へ移動
for item in "$SRC"/*(N); do
  base="${item:t}"
  if [[ "$base" =~ '^[0-9]{16}_[0-9]{14}\.zip$' ]]; then
    s1=$(stat -f %z "$item"); sleep 2; s2=$(stat -f %z "$item")
    [[ "$s1" != "$s2" ]] && continue          # ダウンロード途中
    if [[ -e "$DEST/$base" ]]; then
      log "同名zipが既にあるためスキップ $base"; continue
    fi
    mv "$item" "$DEST/"
    if ditto -x -k "$DEST/$base" "$DEST"; then
      log "格納・解凍 $base"
    else
      log "解凍失敗 $base"
    fi
  elif [[ -d "$item" && "$base" =~ '^[0-9]{16}_[0-9]{14}$' ]]; then
    if [[ -e "$DEST/$base" ]]; then
      log "同名フォルダが既にあるためスキップ $base"
    else
      mv "$item" "$DEST/"
      log "格納 $base"
    fi
  fi
done

# 2. 保存先内の、XSL指定のあるXMLをPDF化(作成済みはスキップ)
find "$DEST" -name '*.xml' | while read -r xml; do
  pdf="${xml%.xml}.pdf"
  [[ -e "$pdf" ]] && continue
  xsl=$(sed -n 's/.*xml-stylesheet[^>]*href="\([^"]*\)".*/\1/p' "$xml" | head -1)
  [[ -z "$xsl" ]] && continue                 # 署名XMLなどは対象外
  dir="${xml:h}"
  [[ -e "$dir/$xsl" ]] || continue
  html="${xml%.xml}.html"
  if xsltproc -o "$html" "$dir/$xsl" "$xml" 2>>"$LOG"; then
    "$CHROME" --headless=new --disable-gpu --no-pdf-header-footer \
      --print-to-pdf="$pdf" "$html" >/dev/null 2>&1
    if [[ -e "$pdf" ]]; then log "PDF作成 $pdf"; else log "PDF作成失敗 $pdf"; fi
  else
    log "XSL変換失敗 $xml"
  fi
done

Macでのセットアップ手順

スクリプト本体は nanoやテキストエディットに貼り付けて保存しない。初回にnanoへ貼り付けたら引用符(" ')が崩れ、unmatched " で動かなかった。テキストエディットも、スマート引用符で " が “ ” に変わる。

場所貼り付けたもの結果
ターミナルのnanoスクリプト全文引用符が崩れて失敗
(Claudeから受け取ったファイル)egov2pdf.sh をダウンロードして ~/bin に移動成功
Automatorの「シェルスクリプトを実行」の欄~/bin/egov2pdf.sh の 1行だけ成功(スクリプト本体はここに貼らない)
  1. Google Chromeをインストールする
  2. このメモの「スクリプト全文」のコードブロックをコピーし、ターミナルで次を実行する(pbpaste はクリップボードの中身をそのままファイルに書き出すので、引用符が崩れない)
mkdir -p ~/bin
pbpaste > ~/bin/egov2pdf.sh
chmod +x ~/bin/egov2pdf.sh
head -3 ~/bin/egov2pdf.sh

最後の行で、1行目が #!/bin/zsh と表示されればOK。

  1. スクリプトの DEST= の行を、自分の保存先に書き換える(VS Codeで開いて編集するのが安全)
  2. Automatorを開き、「新規書類」→「フォルダアクション」を選ぶ
  3. 「フォルダアクションが受け取る項目」で「ダウンロード」を指定する
  4. 「ユーティリティ」→「シェルスクリプトを実行」をドラッグする。シェルは /bin/zsh、入力の引き渡し方法は「引数として」、本文は ~/bin/egov2pdf.sh の1行だけ
  5. 「e-Gov公文書PDF化」という名前で保存する
  6. フルディスクアクセスの画面を開き、「+」→ command + shift + G → /System/Library/CoreServices/Folder Actions Dispatcher.app を追加してオンにする
open "x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles"
killall "Folder Actions Dispatcher"
  1. 公文書zipを1つダウンロードフォルダに入れて、ログに「格納・解凍」と「PDF作成」が出ればOK

手動実行・確認コマンド

やりたいことコマンド
手動で実行(溜まった分をまとめて処理)~/bin/egov2pdf.sh
直近のログを見るtail -10 ~/Documents/〇〇/G-GOV電子申請/_egov2pdf_log.txt
保存先を開くopen ~/Documents/〇〇/G-GOV電子申請
できたPDFの一覧find ~/Documents/〇〇/G-GOV電子申請 -name '*.pdf'
ダウンロードに残っている対象ls ~/Downloads | grep -E '^[0-9]{16}_[0-9]{14}'
動作テスト(既存zipを一度ダウンロードに戻す)mv ~/Documents/〇〇/G-GOV電子申請/<zip名> ~/Downloads/

古いzipが解凍されていないときは、Finderでzipをダブルクリックして解凍してから ~/bin/egov2pdf.sh を実行すれば、PDFが作成される。

トラブルシューティング

困ったらまずログを見る。ログに何も出ていなければ、スクリプトが起動していないか、権限で止まっている。

症状原因対処
unmatched " で止まるnanoへの貼り付けで引用符が崩れたスクリプトはファイルで持ち込む
zipが見つからず、同じ名前のフォルダだけあるSafariの「ダウンロード後、”安全な”ファイルを開く」で自動解凍されたスクリプトは解凍済みフォルダにも対応済み。設定変更は不要
解凍まではできるが、PDFもログも無いフォルダアクションに「書類」へのアクセス権が無い(operation not permitted)Folder Actions Dispatcher にフルディスクアクセスを付け、killall "Folder Actions Dispatcher" を実行
zipがダウンロードに残ったままフォルダアクションが無効、または未設定ダウンロードを右クリック →「サービス」→「フォルダアクション設定…」で、有効化と割り当てを確認
「同名zip(フォルダ)が既にあるためスキップ」同じ公文書を再ダウンロードしたダウンロードに残ったものは手で削除してOK
PDFのレイアウトが崩れるXSLが外部ファイルを参照している可能性未発生。起きたら該当のxsl・xmlを確認

原因を細かく追うときは、スクリプトの2行目に次を一時的に入れると、動作が1行ずつ ~/bin/egov2pdf_debug.log に残る。終わったら消す。

exec >> "$HOME/bin/egov2pdf_debug.log" 2>&1
set -x

あー よくわからんかったが動いた。来月分が問題なく稼働することを願う。

NOTICES

  • 記事内容は実装させたものがほとんどですが自己責任で参考にしてください。