Google Doc自動化 - テンプレートで週次レポートを追記する
指定されたスケジュールでGoogle Docにテンプレートを追記するGoogle Apps Scriptの自動化の例です。
ソースのGoogle Docのコンテンツを、指定されたフレーズの後に別のGoogle Docに挿入するGoogle Apps Scriptの自動化です。
- テンプレートが入っているGoogle Docを「ソース」Google Docと呼びます。
- テンプレートを受け取るGoogle Docを「ターゲット」Google Docと呼びます。
この自動化でできること
- このスクリプトは、1つのGoogle Doc(ソース)のコンテンツを、特定のフレーズの後に別のGoogle Doc(ターゲット)に挿入します。
- Google Apps ScriptのDocumentAppサービスを使ってGoogle Docsを操作します。
- スクリプトを毎週実行するように設定できます。
Google Apps Scriptコード
js
/**
* Inserts content from a source Google Doc into a target Google Doc after a specified phrase.
* Versions:
* + 1.0.4 (2025-03-14): Fixed empty separator handling; no additional line breaks for empty separators.
* + 1.0.3 (2025-03-13): Fixed bullet list issue; improved list item handling.
* + 1.0.2 (2025-03-13): Polished code; added more element-specific handling.
*
* @param {string} srcDocId - Source Google Doc's ID.
* @param {string} targetDocId - Target Google Doc's ID.
* @param {string} insertLocation - Phrase in the target Google Doc after which content will be inserted.
* @param {string} separator - Optional separator text for clarity.
*/
function insertDocContentAfterPhrase() {
const srcDocId = 'SOURCE_GOOGLE_DOC_ID';
const targetDocId = 'TARGET_GOOGLE_DOC_ID';
const insertLocation = 'Insert Below:';
const separator = '----------------------';
const srcDoc = DocumentApp.openById(srcDocId).getBody();
const targetBody = DocumentApp.openById(targetDocId).getBody();
// Find the paragraph index that contains the insert location phrase.
const targetParagraphs = targetBody.getParagraphs();
const targetIndex = targetParagraphs.findIndex((paragraph) =>
paragraph.getText().includes(insertLocation),
);
if (targetIndex === -1) {
Logger.log('Phrase not found in the target document.');
return;
}
let insertIndex = targetIndex + 1;
// Insert a separator for clarity only if it's non-empty
if (separator.trim()) {
targetBody.insertParagraph(insertIndex, separator);
insertIndex++;
}
// Build an array of source elements using Array.from.
const srcElements = Array.from({ length: srcDoc.getNumChildren() }, (_, j) =>
srcDoc.getChild(j),
);
// Helper function to insert elements based on type.
const insertElement = (element, index) => {
switch (element.getType()) {
case DocumentApp.ElementType.INLINE_IMAGE:
targetBody.insertImage(index, element.copy());
break;
case DocumentApp.ElementType.PAGE_BREAK:
targetBody.insertPageBreak(index, element.copy());
break;
case DocumentApp.ElementType.PARAGRAPH:
targetBody.insertParagraph(index, element.copy());
break;
case DocumentApp.ElementType.TABLE:
targetBody.insertTable(index, element.copy());
break;
case DocumentApp.ElementType.LIST_ITEM: {
const newListItem = targetBody.insertListItem(index, element.getText());
newListItem.setAttributes(element.getAttributes());
newListItem.setGlyphType(element.getGlyphType());
break;
}
default:
console.log('Element type not supported: ' + element.getType());
targetBody.insertParagraph(index, element.copy()); // Insert as a paragraph by default.
break;
}
};
// Insert each source element into the target document.
srcElements.forEach((element) => {
insertElement(element, insertIndex);
insertIndex++;
});
Logger.log('Content inserted successfully after the target phrase.');
}セットアップ手順
- Google Apps Scriptプロジェクトを作成する
- Google Driveを開く → + 新規 → その他 → Google Apps Scriptをクリックします。
- 上記のスクリプトを貼り付けます。
- Google Doc IDを追加する
- プレースホルダーの
SOURCE_GOOGLE_DOC_IDとTARGET_GOOGLE_DOC_IDを実際のGoogle Doc IDに置き換えます。 - Google Doc IDはドキュメントのURLに含まれる一意の識別子です。例えば、
https://docs.google.com/document/d/1_h0aQdM1mBSZawk2stu9Ng_TCZm4UvsFJ9y5prYuCtU/editの場合、IDは1_h0aQdM1mBSZawk2stu9Ng_TCZm4UvsFJ9y5prYuCtUです。
- プレースホルダーの
- ターゲットフレーズを置き換える
Insert Below:を、テンプレートを挿入したいターゲットGoogle Doc内のフレーズに置き換えます。
- スクリプトを保存する
- ファイル → 保存をクリックします。
- 毎週実行するトリガーを設定する
- Apps Scriptのトリガー(時計アイコン)をクリックします。
- + トリガーを追加をクリックします。
- 関数を選択:
insertDocContentAfterPhrase - イベントのソースを選択:時間主導型
- タイプを選択:週タイマー
- 実行する曜日と時間を選択します。
IMPORTANT
Google Docの権限:スクリプトがソースとターゲットの両方のドキュメントにアクセス・変更できる権限があることを確認してください。スクリプトを実行する前に、共有権限を適切に設定してください。
コードの説明
変数
srcDocId:ソースGoogle Docの一意の識別子です。targetDocId:ターゲットGoogle Docの一意の識別子です。insertLocation:ターゲットドキュメント内の大文字小文字を区別する文字列で、この文字列の下に新しいコンテンツが挿入されます。このフレーズが複数ある場合、最初の出現箇所の後にコンテンツが挿入されます。separator:視覚的な区切り線として使用されるハードコードされた値です(オプション)。コードは分かりやすさのため、区切りテキストの代わりに空の段落を挿入します。
ソースとターゲットのGoogle Docからコンテンツを取得する
javascript
const srcDoc = DocumentApp.openById(srcDocId).getBody();
const targetBody = DocumentApp.openById(targetDocId).getBody();srcDocIdとtargetDocId変数で指定された識別子を使って、これらのGoogle Docsファイルを特定します。DocumentAppサービスを使って、ソースとターゲットの両方のGoogle Docsを開きます。getBody()メソッドで各ドキュメントのメインコンテンツ(本文)を取得します。本文にはドキュメントを構成するすべての段落、テーブル、その他の要素が含まれています。
挿入ポイントの確認と検索
javascript
const targetParagraphs = targetBody.getParagraphs();
const targetIndex = targetParagraphs.findIndex((paragraph) =>
paragraph.getText().includes(insertLocation),
);
if (targetIndex === -1) {
Logger.log('Phrase not found in the target document.');
return;
}
let insertIndex = targetIndex + 1;getParagraphs()メソッドを使って、ターゲットドキュメント内のすべての段落の配列を取得します。findIndex()メソッドを使って、指定されたマーカーフレーズ(insertLocation)を含む段落を検索します。フレーズが見つからない場合は、エラーメッセージをログに記録して関数を終了します。- フレーズが見つかった場合、マーカーを含む段落の直後を挿入ポイント(
insertIndex)として計算します。
IMPORTANT
insertLocationの値は大文字小文字を区別する文字列で、ターゲットドキュメント内の正確なテキストと一致する必要があります。エラーを防ぐため、マーカーフレーズが正しく指定されていることを確認してください。
セパレーターの挿入とソース要素配列の構築
javascript
// Insert a separator for clarity
targetBody.insertParagraph(insertIndex, separator);
insertIndex++;
// Build an array of source elements using Array.from.
const srcElements = Array.from({ length: srcDoc.getNumChildren() }, (_, j) =>
srcDoc.getChild(j),
);- 挿入ポイントに
separator変数に格納された文字列とともに空の段落を挿入し、既存のコンテンツと新しいコンテンツを視覚的に区切ります。 getNumChildren()メソッドを使って、ソースドキュメント内の要素数を取得します。Array.from()メソッドを使って、ソースドキュメントからコピーされた要素の配列を作成します。copy()メソッドを使って各要素の複製を作成し、元のソースドキュメントが変更されないようにします。
TIP
.setBold(true)や.setUnderline(true)を追加して、セパレーター行を目立たせるようにフォーマットできます。
コピーしたコンテンツをターゲットドキュメントに挿入する
javascript
const insertElement = (element, index) => {
switch (element.getType()) {
case DocumentApp.ElementType.INLINE_IMAGE:
targetBody.insertImage(index, element.copy());
break;
case DocumentApp.ElementType.PAGE_BREAK:
targetBody.insertPageBreak(index, element.copy());
break;
case DocumentApp.ElementType.PARAGRAPH:
targetBody.insertParagraph(index, element.copy());
break;
case DocumentApp.ElementType.TABLE:
targetBody.insertTable(index, element.copy());
break;
case DocumentApp.ElementType.LIST_ITEM: {
const newListItem = targetBody.insertListItem(index, element.getText());
newListItem.setAttributes(element.getAttributes());
newListItem.setGlyphType(element.getGlyphType());
break;
}
default:
console.log('Element type not supported: ' + element.getType());
targetBody.insertParagraph(index, element.copy()); // Insert as a paragraph by default.
break;
}
};forEach()メソッドを使って、ソースドキュメントからコピーした各要素を反復処理します。getType()メソッドを使って、各要素のタイプ(段落、テーブル、リストアイテム)を判定します。switch文を使って各要素タイプを処理します。- インライン画像の場合、
insertImage()を使ってターゲットドキュメントに挿入します。 - ページブレークの場合、
insertPageBreak()を使って挿入します。 - 段落の場合、
insertParagraph()を使ってターゲットドキュメントに挿入します。 - テーブルの場合、
insertTable()を使って挿入します。 - リストアイテムの場合、
insertListItem()を使って挿入します。フォーマットが失われないように、ソースのリストアイテムから属性とグリフタイプを新しいリストアイテムにコピーします。
- インライン画像の場合、
- デフォルトでは段落として挿入します。
- ヘルパー関数
insertElementは、各要素のタイプをチェックして適切な挿入メソッドを使用します。インライン画像、ページブレーク、段落、テーブル、リストアイテムを処理します。リストアイテムには追加のフォーマットを適用します。
各要素をターゲットドキュメントに挿入する
javascript
srcElements.forEach((element) => {
insertElement(element, insertIndex);
insertIndex++;
});srcElements配列内の各要素を反復処理します。- 各要素に対して
insertElement()関数を呼び出し、指定されたインデックスの位置にターゲットドキュメントに挿入します。 - 各要素の挿入後に
insertIndexをインクリメントして、要素が正しい順序で挿入されるようにします。
成功メッセージをログに記録する
javascript
Logger.log('Content inserted successfully after the target phrase.');- すべての要素がターゲットドキュメントに挿入された後、コンテンツが正常に挿入されたことを示すログメッセージが生成されます。