※本記事はプロモーションを含みます
目次
スプレッドシートはGoogleが提供するWeb表計算ツールです。レポートや見積書や請求書をPDF形式に変換して社内保管したり顧客に送付したりする作業は頻繁に発生します。ブラウザのファイルメニューから1操作ずつ手動で書き出す方法もあります。ただし対象の枚数が増えたり毎日や毎月のルーチンワークになったりすると、手作業による手間や誤操作のリスクが無視できなくなります。なので特定の単一シートだけを狙って書き出す処理を自動化します。というのはGASを利用してプログラム側からWebエンドポイント経由でレンダリング結果を取得する手法が極めて有効だからです。今回はアクティブなシートを自動的にPDFへ変換してGoogleドライブへ出力する具体的な記述方法を解説します。なので実行時に生じる権限問題やレイアウト崩れを防ぐためのノウハウも合わせて確認しましょう。
業務で特定のシートだけをPDF化して保存したい場面
スプレッドシートには集計用のデータシートや設定用シートや出力用の帳票シートなど用途の異なる複数のシートが混在します。業務で相手に送付したり保管したりしたいのは、通常そのうちの帳票用シート1枚だけです。なので他の計算過程や参照データを見せる必要はありません。手動操作でPDF出力を行う際にも現在のシートを選択する手順を踏みます。ただしこれを自動処理に組み込む場合も全く同様の制御が求められます。
日次や月次で定期的に生成されるレポートを自動アーカイブする場合は、GASのシートPDF書き出しの仕組みを導入しましょう。フォームの送信結果を受けて即座にPDF化し関係者に共有する場合も同様です。人間が介在すると余計なシートを含めた状態で保存してしまいます。なので保存先のフォルダを間違えるような人的ミスが発生しやすくなります。GASによって指定のシートIDだけを指し示して出力を行えば、常に正確な1枚のシートだけを抽出して保管できるようになります。
業務で利用するスクリプトにおいてはどのシートを対象にするかを動的に判定することが多くなります。現在操作中のシートをそのまま対象にするケースがあります。なので名前で検索したシートのIDを取得して処理に回すケースなど用途に応じた柔軟な実装が必要です。まずは最も基本的なパターンである現在アクティブになっているシートを取得して、そのシートのみをPDFとして書き出す処理の構成を確認しましょう。
Webエンドポイント呼び出しによる自動生成処理
画面上のアクティブなシートだけを選択し、そのままドライブ直下にPDFファイルとして保管したいときに実行します。
const ss = SpreadsheetApp.getActiveSpreadsheet();/*省略*/
上記の処理ではスプレッドシートの標準機能であるWeb書き出し機能をUrlFetchApp経由で呼び出しています。スプレッドシートのIDと対象シートのIDであるgidを組み立ててリクエストを送ります。なので該当シートのみがレンダリングされたPDFのバイナリデータを取得できます。このとき重要なのはScriptApp.getOAuthToken()を用いてリクエストヘッダーにアクセストークンを付与している点です。というのはGoogleのアクセス制限を通過するためには実行中のユーザー権限を証明するBearerトークンが不可欠だからです。
ただしこのシンプルなコードのまま運用を始めるといくつか考慮すべき点があります。UrlFetchAppで指定したURLは、現在開いているスプレッドシートのデフォルトの印刷設定に従ってレンダリングされます。なのでシート側で事前に用紙サイズや向きや余白などの設定を行っていない場合、出力されたPDFの見た目が意図したものと大きくかけ離れることがあります。OAuthトークンの有効期限や権限スコープの設定によってアクセス拒否エラーの401 Unauthorizedが発生して処理が停止する事例もあります。なのでコードを実行する環境の認証状態と出力結果の見た目のコントロールは事前によく確認しましょう。
レイアウトや改ページが想定と異なる原因とその対策
実際にこの方式で生成されたPDFを確認すると右側の列が途中ではみ出して次のページに送られていることがあります。余白が大きすぎて全体的に小さく印刷されることもあります。なのでグリッド線が表示されていて帳票らしくないといった見た目の不具合に直面します。手動でPDF化する際には設定画面上で幅に合わせる設定や横向きや枠線なしといった調整を行えます。ただし基本URLのままリクエストを送ると、これらのオプションがデフォルト値で処理されてしまいます。
このレイアウトがずれる点を回避するためにはexport URLの後ろに印刷制御用のパラメータを明示的に付与します。用紙サイズを指定する size=A4 や用紙の向きを横にする portrait=false を使います。シートの幅を1ページに収める fitw=true や枠線を非表示にする gridlines=false などのオプション文字列を & で連結してURLを作成します。なのでコード側から出力時の見た目を直接指定できるようになります。だから毎回安定した見た目のPDFを生成することが可能になります。
ただしURLパラメータによる制御にも限界が存在します。スプレッドシート側で動的に計算される複雑な改ページ位置はパラメータだけでは完全に解決できない場合があります。特殊なフォントの文字化けや折り返し位置の不整合も同様です。確実に意図通りのPDFを出力するためにはあらかじめ対象シートの表示モードを調整します。なので列幅や行高をピクセル単位で余裕を持って設計しておきましょう。GASによる出力結果だけに頼るのではなく、元となるシートのデザイン自体をPDF出力に耐えうるレイアウトにしておくことが最大のトラブル回避策です。
権限エラーや実行制限で処理が止まる問題への対処法
処理を実行した際に401 Unauthorizedや403 Forbiddenといったエラーが発生してPDFが生成されないケースがあります。この問題の主な原因はGASプロジェクトに割り当てられているOAuthスコープが足りないことです。UrlFetchAppを通じたGoogleドライブやスプレッドシートの内部APIアクセスに必要なレベルに達していません。スクリプトエディタの標準状態ではコード内で直接使用されているSpreadsheetAppやDriveAppの権限のみが自動検出されます。ただしUrlFetchAppで自分自身のファイルをHTTP経由で取得する動作は特殊な権限を要求します。
この権限不足を回避するためにはマニフェストファイルのappsscript.jsonを編集して明示的に必要なOAuthスコープを設定します。具体的には https://www.googleapis.com/auth/drive や https://www.googleapis.com/auth/spreadsheets といったスコープを oauthScopes 配列に記述します。なのでスクリプト実行に必要な全ての操作権限を確実に確保できます。ダミーのコメントとして DriveApp.getFiles() のような記述をコード内に入れておく手法もあります。というのはGASの自動スコープ検出機能にドライブアクセスの必要性を認識させられるからです。
さらにGASには実行時間制限やリクエスト回数の上限が存在します。大量のシートをループ処理で順番にPDF化して書き出すような仕様にした場合、UrlFetchAppの連続呼び出しによって処理時間が上限を超過します。なのでGoogle側のレート制限に引っかかったりします。単一の実行で数十枚以上のPDFを連続生成するような業務設計は避けましょう。処理を分割してトリガーで実行するか、必要なシートだけを厳選して処理する構造に設計し直すのが賢明です。
ファイル名の重複防止と特定フォルダへの保存方法
提示したコードの例では DriveApp.getRootFolder().createFile(blob) を使用しています。なので生成されたPDFファイルは常に実行者のマイドライブの直下に保存されます。ただし実務の運用においてマイドライブ直下に大量のファイルが乱立する状態は望ましくありません。多くの場合、特定の業務用共有フォルダや年・月ごとに整理された専用フォルダにファイルを直接格納する仕様が求められます。
マイドライブ直下ではなく指定のフォルダに保存したい場合はフォルダIDを指定して DriveApp.getFolderById(folderId) で対象フォルダオブジェクトを取得します。なのでそのフォルダに対して createFile(blob) を呼び出すように変更しましょう。自動生成されたファイルが正しい階層に分類されます。だからチーム内での情報共有や検索が著しくスムーズになります。同名のファイルが既に存在する場合に上書きされるのではなく同一名称の別ファイルとして新規作成されるGoogleドライブの仕様にも注意が必要です。
同一フォルダ内に同名ファイルが蓄積して混乱するのを回避するためにはファイル名にタイムスタンプや一連番号を自動付与しましょう。sheet.getName() + “_” + Utilities.formatDate(new Date(), “JST”, “yyyyMMdd_HHmmss”) + “.pdf” のように保存日時を組み合わせた名称を設定します。なので過去の履歴を正確に保持しつつファイルの一致による誤認を防ぐことができます。適切な保存先の管理とファイル名の命名規則の確立は、自動化処理を長期間安定して稼働させるための重要な要素です。

