Google Apps Script: Полный курс для разработчиков (с примерами)

Что такое Google Apps Script и для чего он нужен?

Google Apps Script (GAS) — это облачная платформа для разработки на JavaScript, позволяющая расширять функциональность приложений Google Workspace (Sheets, Docs, Forms, Gmail, Calendar и др.) и автоматизировать рабочие процессы. GAS предоставляет удобный способ интеграции различных сервисов Google и внешних API без необходимости развертывания собственной инфраструктуры.

Основная цель GAS — упростить создание кастомных решений, которые взаимодействуют с экосистемой Google. Это может быть автоматизация рутинных задач, создание пользовательских меню и интерфейсов, обработка данных, генерация отчетов, интеграция со сторонними сервисами и многое другое.

Преимущества использования Google Apps Script

  • Интеграция: Глубокая интеграция с сервисами Google Workspace «из коробки».
  • Простота: Основан на JavaScript, что делает его доступным для широкого круга разработчиков. Не требует управления серверами.
  • Бесплатность: Большинство квот и возможностей доступны бесплатно в рамках стандартных аккаунтов Google.
  • Расширяемость: Возможность подключения к внешним API и базам данных через JDBC или UrlFetch Service.
  • Автоматизация: Мощные триггеры (по времени, по событиям) для запуска скриптов.

Настройка среды разработки: редактор скриптов Google

Для начала работы не требуется установка дополнительного ПО. Редактор скриптов доступен непосредственно из приложений Google Workspace (например, в Google Sheets: «Расширения» -> «Apps Script»).

Редактор предоставляет базовые функции: подсветку синтаксиса, автодополнение (с учетом типов через JSDoc), отладчик, управление версиями и развертыванием. Современный редактор поддерживает функции, схожие с VS Code, включая улучшенное автодополнение и проверку кода.

Первый скрипт: основы синтаксиса и структуры

Скрипты GAS пишутся на JavaScript (поддерживается синтаксис ES6+). Каждый скрипт состоит из одного или нескольких файлов .gs. Функции в этих файлах могут вызываться вручную, через триггеры или из пользовательского интерфейса.

/**
 * Записывает приветственное сообщение в лог.
 * @param {string} name Имя для приветствия.
 * @returns {void}
 */
function logGreeting(name: string): void {
  const message: string = `Привет, ${name}! Добро пожаловать в Google Apps Script.`;
  Logger.log(message); // Вывод в лог выполнения (Ctrl+Enter или Cmd+Enter)
}

/**
 * Основная функция для демонстрации.
 */
function runExample(): void {
  logGreeting('Разработчик');
}

Работа с Google Sheets

Чтение и запись данных в таблицы Google

Сервис SpreadsheetApp является точкой входа для взаимодействия с Google Sheets. Он позволяет получать доступ к активной таблице, конкретным листам, диапазонам ячеек и их значениям.

/**
 * Читает данные из указанного диапазона листа.
 * @param {string} sheetName Имя листа.
 * @param {string} rangeA1 Диапазон в нотации A1 (например, "A1:C10").
 * @returns {any[][]} Двумерный массив со значениями ячеек.
 */
function readSheetData(sheetName: string, rangeA1: string): any[][] {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheet = ss.getSheetByName(sheetName);
  if (!sheet) {
    Logger.log(`Лист с именем "${sheetName}" не найден.`);
    return [];
  }
  const range = sheet.getRange(rangeA1);
  return range.getValues();
}

/**
 * Записывает данные в указанный диапазон листа.
 * @param {string} sheetName Имя листа.
 * @param {string} startCell Начальная ячейка для записи (например, "A1").
 * @param {any[][]} data Двумерный массив данных для записи.
 * @returns {void}
 */
function writeSheetData(sheetName: string, startCell: string, data: any[][]): void {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheet = ss.getSheetByName(sheetName);
  if (!sheet || !data || data.length === 0 || data[0].length === 0) {
    Logger.log('Ошибка: Лист не найден или данные некорректны.');
    return;
  }
  const startRow = sheet.getRange(startCell).getRow();
  const startCol = sheet.getRange(startCell).getColumn();
  const numRows = data.length;
  const numCols = data[0].length;
  sheet.getRange(startRow, startCol, numRows, numCols).setValues(data);
  Logger.log(`Данные (${numRows}x${numCols}) успешно записаны в ${sheetName}!${startCell}.`);
}

Форматирование данных и создание диаграмм

GAS позволяет управлять форматированием ячеек (шрифт, цвет, границы, числовые форматы) через методы объекта Range. Также можно программно создавать и изменять диаграммы на листах, используя сервис Charts и методы Sheet.insertChart().

/**
 * Применяет базовое форматирование к заголовкам таблицы.
 * @param {GoogleAppsScript.Spreadsheet.Range} headerRange Диапазон заголовков.
 * @returns {void}
 */
function formatHeaders(headerRange: GoogleAppsScript.Spreadsheet.Range): void {
  headerRange
    .setBackground('#cfe2f3') // Светло-голубой фон
    .setFontWeight('bold')
    .setHorizontalAlignment('center');
}

/**
 * Создает простую линейную диаграмму на листе.
 * @param {GoogleAppsScript.Spreadsheet.Sheet} sheet Лист для вставки диаграммы.
 * @param {GoogleAppsScript.Spreadsheet.Range} dataRange Диапазон данных для диаграммы.
 * @param {string} title Заголовок диаграммы.
 * @returns {GoogleAppsScript.Spreadsheet.EmbeddedChart | null} Созданная диаграмма или null в случае ошибки.
 */
function createLineChart(sheet: GoogleAppsScript.Spreadsheet.Sheet, dataRange: GoogleAppsScript.Spreadsheet.Range, title: string): GoogleAppsScript.Spreadsheet.EmbeddedChart | null {
  if (!sheet || !dataRange) return null;

  const chartBuilder = sheet.newChart()
    .setChartType(Charts.ChartType.LINE)
    .addRange(dataRange)
    .setPosition(5, 5, 0, 0) // Позиция относительно верхнего левого угла
    .setOption('title', title)
    .setOption('useFirstColumnAsDomain', true) // Использовать первую колонку как ось X
    .build();

  sheet.insertChart(chartBuilder);
  Logger.log(`Диаграмма "${title}" создана.`);
  return chartBuilder;
}

Триггеры: автоматическое выполнение скриптов в Google Sheets

Триггеры позволяют запускать функции автоматически при наступлении определенных событий:

  • Простые триггеры: onOpen(e), onEdit(e), onInstall(e). Выполняются с ограниченными правами.
  • Устанавливаемые триггеры: Настраиваются программно (ScriptApp.newTrigger()) или через интерфейс редактора. Могут запускаться по времени (ежедневно, ежечасно), при открытии таблицы, при изменении данных, при отправке формы. Требуют авторизации пользователя.

Примеры скриптов для автоматизации задач в Google Sheets (обработка данных, импорт/экспорт)

  • Обработка данных: Скрипт, который при изменении данных в столбце «Статус» автоматически переносит строку на другой лист.
  • Импорт CSV: Функция, которая загружает CSV-файл из Google Drive и парсит его содержимое в таблицу.
  • Агрегация данных: Ежедневный запуск скрипта, который собирает данные с нескольких листов (например, по рекламным кампаниям) и формирует сводный отчет на отдельном листе.
/**
 * Пример: Импортирует данные из CSV файла в Google Drive.
 * @param {string} fileId ID CSV файла в Google Drive.
 * @param {string} targetSheetName Имя листа для импорта данных.
 * @returns {void}
 */
function importCsvFromDrive(fileId: string, targetSheetName: string): void {
  try {
    const file = DriveApp.getFileById(fileId);
    const csvContent = file.getBlob().getDataAsString('UTF-8'); // Указываем кодировку
    const csvData = Utilities.parseCsv(csvContent);

    if (csvData.length === 0) {
      Logger.log('CSV файл пуст или не удалось его распарсить.');
      return;
    }

    const ss = SpreadsheetApp.getActiveSpreadsheet();
    let sheet = ss.getSheetByName(targetSheetName);
    if (!sheet) {
      sheet = ss.insertSheet(targetSheetName);
    }
    sheet.clearContents(); // Очищаем лист перед записью
    sheet.getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
    Logger.log(`Данные из файла ID ${fileId} успешно импортированы в лист "${targetSheetName}".`);

  } catch (e: any) {
    Logger.log(`Ошибка при импорте CSV: ${e.message}\n${e.stack}`);
  }
}

Взаимодействие с Google Docs и Slides

Создание, редактирование и форматирование документов Google Docs

Сервис DocumentApp позволяет работать с Google Docs. Можно создавать новые документы, открывать существующие, добавлять и форматировать текст, абзацы, списки, таблицы, изображения.

/**
 * Создает новый Google Doc с заголовком и текстом.
 * @param {string} docName Имя нового документа.
 * @param {string} title Заголовок документа.
 * @param {string} bodyText Текст основного содержимого.
 * @returns {string} URL созданного документа.
 */
function createSimpleDoc(docName: string, title: string, bodyText: string): string {
  const doc = DocumentApp.create(docName);
  const body = doc.getBody();

  // Добавляем заголовок H1
  body.appendParagraph(title)
      .setHeading(DocumentApp.ParagraphHeading.HEADING1);

  // Добавляем основной текст
  body.appendParagraph(bodyText);

  doc.saveAndClose();
  Logger.log(`Документ "${docName}" создан: ${doc.getUrl()}`);
  return doc.getUrl();
}

/**
 * Добавляет таблицу в существующий документ.
 * @param {string} docId ID документа.
 * @param {string[][]} data Данные для таблицы (массив массивов).
 * @returns {void}
 */
function addTableToDoc(docId: string, data: string[][]): void {
  if (!data || data.length === 0) return;
  const doc = DocumentApp.openById(docId);
  const body = doc.getBody();
  body.appendTable(data);
  doc.saveAndClose();
  Logger.log(`Таблица добавлена в документ ID ${docId}.`);
}

Работа с презентациями Google Slides: добавление слайдов и элементов

Сервис SlidesApp предназначен для работы с Google Slides. Он позволяет создавать презентации, добавлять слайды на основе макетов, вставлять текст, фигуры, изображения, таблицы и видео.

/**
 * Добавляет новый слайд с заголовком и текстом в презентацию.
 * @param {string} presentationId ID презентации.
 * @param {string} slideTitle Заголовок слайда.
 * @param {string} slideBody Текст на слайде.
 * @returns {void}
 */
function addSlide(presentationId: string, slideTitle: string, slideBody: string): void {
  const pres = SlidesApp.openById(presentationId);
  const slideLayout = pres.getLayouts()[1]; // Используем второй макет (например, Title and Body)
  const slide = pres.appendSlide(slideLayout);

  // Вставляем текст в плейсхолдеры
  const titlePlaceholder = slide.getPlaceholder(SlidesApp.PlaceholderType.TITLE);
  if (titlePlaceholder) {
      titlePlaceholder.asShape().getText().setText(slideTitle);
  }

  const bodyPlaceholder = slide.getPlaceholder(SlidesApp.PlaceholderType.BODY);
  if (bodyPlaceholder) {
      bodyPlaceholder.asShape().getText().setText(slideBody);
  }

  Logger.log(`Слайд "${slideTitle}" добавлен в презентацию ID ${presentationId}.`);
}

Автоматизация создания отчетов и презентаций на основе данных

Одна из самых мощных возможностей GAS — генерация документов и презентаций на основе данных из Google Sheets или других источников. Можно создать шаблон документа или слайда с плейсхолдерами ({{placeholder}}) и затем программно заменять их на реальные данные.

Реклама
/**
 * Генерирует отчет в Google Doc на основе данных из строки таблицы.
 * @param {string} templateDocId ID документа-шаблона.
 * @param {Record<string, string>} data Данные для замены плейсхолдеров (ключ: плейсхолдер, значение: текст).
 * @param {string} outputDocName Имя генерируемого документа.
 * @returns {string | null} URL созданного документа или null.
 */
function generateDocFromTemplate(templateDocId: string, data: Record<string, string>, outputDocName: string): string | null {
  try {
    const templateDoc = DriveApp.getFileById(templateDocId);
    const newDocFile = templateDoc.makeCopy(outputDocName);
    const newDoc = DocumentApp.openById(newDocFile.getId());
    const body = newDoc.getBody();

    for (const placeholder in data) {
      body.replaceText(`{{${placeholder}}}`, data[placeholder]);
    }

    newDoc.saveAndClose();
    const url = newDoc.getUrl();
    Logger.log(`Отчет "${outputDocName}" сгенерирован: ${url}`);
    return url;
  } catch (e: any) {
    Logger.log(`Ошибка генерации документа: ${e.message}`);
    return null;
  }
}

Примеры скриптов для работы с текстом и изображениями

  • Замена текста: Найти и заменить определенные слова или фразы во всех документах в папке.
  • Вставка изображений: Добавить логотип компании или изображения продуктов в документ/презентацию из Google Drive или по URL.
  • Анализ текста: Подсчет количества слов или символов в документе.

Автоматизация Gmail и Google Calendar

Отправка и обработка писем с помощью Gmail API

Сервис GmailApp предоставляет доступ к ящику Gmail. Можно отправлять письма (простые и HTML), искать письма по критериям, получать содержимое писем, управлять метками и перемещать письма.

/**
 * Отправляет email.
 * @param {string} recipient Адрес получателя.
 * @param {string} subject Тема письма.
 * @param {string} body Текст письма (может быть HTML).
 * @param {GmailApp.GmailAdvancedOptions | undefined} options Дополнительные параметры (cc, bcc, htmlBody, attachments и т.д.).
 * @returns {void}
 */
function sendEmail(recipient: string, subject: string, body: string, options?: GmailApp.GmailAdvancedOptions): void {
  try {
    GmailApp.sendEmail(recipient, subject, body, options);
    Logger.log(`Письмо отправлено на ${recipient}.`);
  } catch (e: any) {
    Logger.log(`Ошибка отправки email: ${e.message}`);
  }
}

/**
 * Ищет письма по запросу и логирует темы найденных писем.
 * @param {string} searchQuery Поисковый запрос Gmail (например, "from:sender@example.com is:unread").
 * @param {number} maxThreads Максимальное количество цепочек для обработки.
 * @returns {void}
 */
function processEmails(searchQuery: string, maxThreads: number = 10): void {
  const threads = GmailApp.search(searchQuery, 0, maxThreads);
  Logger.log(`Найдено ${threads.length} цепочек писем по запросу "${searchQuery}".`);

  threads.forEach(thread => {
    const firstMessage = thread.getMessages()[0]; // Берем первое сообщение в цепочке
    Logger.log(` - Тема: ${firstMessage.getSubject()}, От: ${firstMessage.getFrom()}`);
    // Здесь можно добавить логику обработки: извлечение данных, добавление метки и т.д.
    // thread.addLabel(GmailApp.getUserLabelByName('Processed'));
    // thread.moveToArchive();
  });
}

Управление событиями в Google Calendar

Сервис CalendarApp позволяет работать с Google Calendar. Можно получать доступ к календарям, создавать, изменять и удалять события, управлять приглашениями и напоминаниями.

/**
 * Создает событие в основном календаре пользователя.
 * @param {string} title Название события.
 * @param {Date} startTime Время начала.
 * @param {Date} endTime Время окончания.
 * @param {CalendarApp.EventOptions | undefined} options Дополнительные параметры (описание, местоположение, гости и т.д.).
 * @returns {GoogleAppsScript.Calendar.CalendarEvent | null} Созданное событие или null.
 */
function createCalendarEvent(title: string, startTime: Date, endTime: Date, options?: CalendarApp.EventOptions): GoogleAppsScript.Calendar.CalendarEvent | null {
  try {
    const calendar = CalendarApp.getDefaultCalendar();
    const event = calendar.createEvent(title, startTime, endTime, options);
    Logger.log(`Событие "${title}" создано (ID: ${event.getId()}).`);
    return event;
  } catch (e: any) {
    Logger.log(`Ошибка создания события: ${e.message}`);
    return null;
  }
}

/**
 * Находит предстоящие события на сегодня.
 * @returns {GoogleAppsScript.Calendar.CalendarEvent[]} Массив событий.
 */
function getTodaysEvents(): GoogleAppsScript.Calendar.CalendarEvent[] {
  const today = new Date();
  const startOfDay = new Date(today.setHours(0, 0, 0, 0));
  const endOfDay = new Date(today.setHours(23, 59, 59, 999));
  const calendar = CalendarApp.getDefaultCalendar();
  const events = calendar.getEvents(startOfDay, endOfDay);
  Logger.log(`Найдено ${events.length} событий на сегодня.`);
  return events;
}

Создание напоминаний и автоматизация рассылок

  • Напоминания: Создание событий в календаре для задач с дедлайнами из Google Sheets.
  • Автоматизация рассылок: Персонализированная рассылка писем на основе списка контактов и данных из таблицы (например, отчеты клиентам, уведомления пользователям).

Примеры скриптов для автоматического ответа на письма и создания событий

  • Автоответчик: Скрипт, который отвечает на письма с определенной темой стандартным сообщением.
  • Создание событий из Sheets: Скрипт, который читает строки из таблицы (например, план маркетинговых активностей с датами) и создает соответствующие события в календаре.

Расширенные возможности и интеграция с другими сервисами

Работа с HTML Service: создание пользовательских интерфейсов

HtmlService позволяет создавать веб-интерфейсы с использованием HTML, CSS и JavaScript (на стороне клиента). Эти интерфейсы могут отображаться как диалоговые окна или боковые панели в Google Sheets, Docs, Forms, или как самостоятельные веб-приложения.

GAS позволяет передавать данные из серверного скрипта в клиентский JavaScript (google.script.run) и наоборот.

// Код в файле Code.gs
/**
 * Отображает простую боковую панель в Google Sheets.
 */
function showSidebar(): void {
  const htmlOutput = HtmlService.createHtmlOutputFromFile('Sidebar')
      .setTitle('Моя панель');
  SpreadsheetApp.getUi().showSidebar(htmlOutput);
}

/**
 * Серверная функция, вызываемая из клиентского скрипта.
 * @param {string} name Имя пользователя.
 * @returns {string} Приветствие.
 */
function getServerGreeting(name: string): string {
  Logger.log(`Запрос приветствия для ${name}`);
  return `Привет с сервера, ${name}!`;
}

// Код в файле Sidebar.html
/*
<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
  </head>
  <body>
    <h1>Тестовая панель</h1>
    <p>Введите имя:</p>
    <input type="text" id="nameInput" />
    <button onclick="callServer()">Отправить</button>
    <p id="response"></p>

    <script>
      function callServer() {
        const name = document.getElementById('nameInput').value;
        google.script.run
          .withSuccessHandler(updateResponse)
          .withFailureHandler(showError)
          .getServerGreeting(name);
      }

      function updateResponse(greeting) {
        document.getElementById('response').innerText = greeting;
      }

      function showError(error) {
        document.getElementById('response').innerText = 'Ошибка: ' + error.message;
      }
    </script>
  </body>
</html>
*/

Использование внешних API: получение данных и интеграция с другими сервисами

Сервис UrlFetchApp позволяет отправлять HTTP(S) запросы к внешним API. Это открывает возможности для интеграции с практически любыми сторонними сервисами: CRM, аналитическими платформами, платежными системами и т.д.

Требуется обработка ответов (часто в формате JSON) и управление аутентификацией (API-ключи, OAuth2).

/**
 * Получает данные из внешнего JSON API.
 * @param {string} apiUrl URL API-эндпоинта.
 * @param {GoogleAppsScript.URL_Fetch.URLFetchRequestOptions | undefined} options Параметры запроса (метод, заголовки, payload).
 * @returns {any | null} Распарсенный JSON-ответ или null в случае ошибки.
 */
function fetchExternalApi(apiUrl: string, options?: GoogleAppsScript.URL_Fetch.URLFetchRequestOptions): any | null {
  try {
    const response = UrlFetchApp.fetch(apiUrl, options);
    const responseCode = response.getResponseCode();
    const responseBody = response.getContentText();

    if (responseCode === 200) {
      return JSON.parse(responseBody);
    } else {
      Logger.log(`Ошибка API запроса (${responseCode}): ${responseBody}`);
      return null;
    }
  } catch (e: any) {
    Logger.log(`Ошибка UrlFetchApp: ${e.message}`);
    return null;
  }
}

/**
 * Пример: получение данных о курсе валют (использует публичное API).
 */
function getExchangeRates(): void {
  const apiUrl = 'https://api.exchangerate-api.com/v4/latest/USD'; // Пример API
  const ratesData = fetchExternalApi(apiUrl);

  if (ratesData && ratesData.rates) {
    Logger.log(`Курс EUR к USD: ${ratesData.rates.EUR}`);
    Logger.log(`Курс RUB к USD: ${ratesData.rates.RUB}`);
    // Данные можно записать в Google Sheets
    // writeSheetData('Курсы валют', 'A1', [[new Date(), ratesData.rates.EUR, ratesData.rates.RUB]]);
  }
}

Развертывание скриптов как веб-приложений

Скрипт можно развернуть как веб-приложение, доступное по уникальному URL. Такие приложения могут обслуживать GET и POST запросы, возвращая HTML (с помощью HtmlService) или текстовые данные (например, JSON, используя ContentService).

Развертывание настраивается в редакторе скриптов. Можно выбрать, кто имеет доступ к приложению (только вы, пользователи домена, любой пользователь) и от чьего имени будет выполняться скрипт (пользователя, обращающегося к приложению, или разработчика).

/**
 * Обрабатывает GET запросы к веб-приложению.
 * Возвращает простой HTML ответ.
 * @param {GoogleAppsScript.Events.DoGet} e Объект события.
 * @returns {GoogleAppsScript.HTML.HtmlOutput} HTML ответ.
 */
function doGet(e: GoogleAppsScript.Events.DoGet): GoogleAppsScript.HTML.HtmlOutput {
  Logger.log(`GET запрос: Параметры = ${JSON.stringify(e.parameter)}`);
  const name = e.parameter.name || 'Гость';
  return HtmlService.createHtmlOutput(`<h1>Привет, ${name}!</h1><p>Это веб-приложение на Google Apps Script.</p>`);
}

/**
 * Обрабатывает POST запросы к веб-приложению.
 * Возвращает JSON ответ.
 * @param {GoogleAppsScript.Events.DoPost} e Объект события.
 * @returns {GoogleAppsScript.Content.TextOutput} JSON ответ.
 */
function doPost(e: GoogleAppsScript.Events.DoPost): GoogleAppsScript.Content.TextOutput {
  Logger.log(`POST запрос: Данные = ${e.postData.contents}`);
  let responseData;
  try {
    const requestData = JSON.parse(e.postData.contents);
    // Обработка данных...
    responseData = { status: 'success', received: requestData };
  } catch (err: any) {
    responseData = { status: 'error', message: 'Invalid JSON format.' };
  }
  return ContentService.createTextOutput(JSON.stringify(responseData))
                     .setMimeType(ContentService.MimeType.JSON);
}

Отладка и обработка ошибок в Google Apps Script

  • Логирование: Logger.log() и console.log() для вывода информации в лог выполнения. Логи доступны в редакторе скриптов.
  • Отладчик: Встроенный отладчик позволяет устанавливать точки останова, пошагово выполнять код и проверять значения переменных.
  • Обработка ошибок: Использование стандартных конструкций try...catch...finally для перехвата и обработки исключений.
  • Stackdriver Logging/Error Reporting: Для более продвинутого мониторинга и анализа ошибок в проектах Google Cloud Platform (GCP), связанных со скриптом.

Тщательная обработка ошибок и логирование критически важны для надежной работы скриптов, особенно тех, что выполняются по триггерам или как веб-приложения.


Добавить комментарий