Google Apps Script: Как получить изображение из URL?

Что такое Google Apps Script и его возможности

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

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

Обзор способов получения изображений из URL в Google Apps Script

Основным инструментом для взаимодействия с внешними ресурсами по URL в Google Apps Script является сервис UrlFetchApp. Он позволяет отправлять HTTP-запросы, включая GET-запросы для получения данных по указанному URL. Для изображений это означает получение двоичных данных файла.

Полученные данные изображения обычно представляются в виде Blob (Binary Large Object). Этот объект содержит необработанные данные файла и информацию о его типе (MIME type). В дальнейшем Blob можно использовать для сохранения файла на Google Drive или вставки непосредственно в документы Google Docs или таблицы Google Sheets.

Необходимые библиотеки и разрешения

Для получения изображений из URL и их последующей обработки потребуются следующие сервисы Google Apps Script:

UrlFetchApp: Для выполнения HTTP-запросов к URL изображения.

DriveApp: (Опционально) Для сохранения изображения на Google Drive.

SpreadsheetApp: (Опционально) Для вставки изображения в Google Sheets.

DocumentApp: (Опционально) Для вставки изображения в Google Docs.

При первом запуске скрипта, использующего эти сервисы, Google запросит у пользователя авторизацию. Необходимо предоставить разрешение на доступ к внешним сервисам (urlfetch) и, при необходимости, разрешение на управление файлами на Google Drive, таблицами или документами.

Получение изображения из URL с использованием UrlFetchApp

Описание сервиса UrlFetchApp

UrlFetchApp — это встроенный сервис GAS, предоставляющий интерфейс для выполнения HTTP(S) запросов. Он позволяет получать содержимое веб-страниц, взаимодействовать с API и, что важно для нашей задачи, загружать файлы, включая изображения, по их URL.

Сервис поддерживает различные методы запросов (GET, POST, PUT, DELETE и т.д.), установку заголовков, обработку ответов и управление параметрами запроса, такими как таймауты и обработка ошибок.

Пример кода: Получение изображения по URL и преобразование в Blob

/**
 * Получает изображение по указанному URL и возвращает его как Blob.
 *
 * @param {string} imageUrl URL изображения для загрузки.
 * @return {GoogleAppsScript.Base.Blob | null} Blob-объект изображения или null в случае ошибки.
 */
function fetchImageAsBlob(imageUrl: string): GoogleAppsScript.Base.Blob | null {
  try {
    // Опции запроса (можно добавить заголовки, таймауты и т.д.)
    const options: GoogleAppsScript.URL_Fetch.URLFetchRequestOptions = {
      method: 'get',
      muteHttpExceptions: true // Важно для обработки ошибок вручную
    };

    // Выполняем запрос
    const response: GoogleAppsScript.URL_Fetch.HTTPResponse = UrlFetchApp.fetch(imageUrl, options);
    const responseCode: number = response.getResponseCode();

    // Проверяем статус ответа
    if (responseCode === 200) {
      const imageBlob: GoogleAppsScript.Base.Blob = response.getBlob();
      // Логгирование типа контента для отладки
      Logger.log(`Изображение успешно получено. Тип контента: ${imageBlob.getContentType()}, Размер: ${imageBlob.getBytes().length} байт`);
      return imageBlob;
    } else {
      Logger.log(`Ошибка получения изображения. URL: ${imageUrl}, Код ответа: ${responseCode}, Сообщение: ${response.getContentText()}`);
      return null;
    }
  } catch (error) {
    // Обработка других ошибок (например, недоступность сервиса UrlFetchApp)
    Logger.log(`Критическая ошибка при запросе к URL ${imageUrl}: ${error}`);
    return null;
  }
}

// Пример использования:
function testFetchImage() {
  const sampleImageUrl = 'https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png'; // Пример URL
  const blob = fetchImageAsBlob(sampleImageUrl);
  if (blob) {
    Logger.log('Blob успешно получен.');
    // Дальнейшие действия с blob (сохранение, вставка и т.д.)
  } else {
    Logger.log('Не удалось получить Blob.');
  }
}

Обработка ошибок при получении изображения (таймауты, неверные URL и т.д.)

При работе с внешними ресурсами важно предусмотреть возможные ошибки. UrlFetchApp.fetch может генерировать исключения или возвращать HTTP-ответы с кодами ошибок.

Неверный URL или ресурс не найден (404): response.getResponseCode() вернет код, отличный от 200. Необходимо проверять этот код.

Таймауты: Запрос может превысить максимальное время ожидания (по умолчанию 30 секунд, максимум 6 минут для платных аккаунтов). Можно настроить таймаут в опциях, но обработка ошибки потребует try...catch.

Проблемы с сетью или сервером: Могут возникать ошибки на уровне сети или сервер может быть временно недоступен (коды 5xx).

Ограничения доступа (403 Forbidden): Некоторые серверы могут блокировать запросы от скриптов Google.

Использование muteHttpExceptions: true в опциях запроса позволяет перехватывать HTTP-ошибки (коды 4xx, 5xx) без генерации исключения скриптом, проверяя response.getResponseCode().

Ограничения UrlFetchApp и способы их обхода

Сервис UrlFetchApp имеет квоты и ограничения:

Количество вызовов в день: Зависит от типа аккаунта (G Suite/Workspace или бесплатный Gmail).

Время выполнения запроса: Максимум 6 минут.

Размер ответа: Ограничен (обычно 50 МБ).

Общий трафик в день.

Если требуется обрабатывать большое количество изображений или работать с очень большими файлами, можно столкнуться с этими лимитами. Возможные обходные пути:

Оптимизация: Запрашивать изображения только при необходимости, кэшировать результаты (например, сохраняя их на Drive и используя ID файла вместо повторной загрузки).

Пакетная обработка: Группировать операции, использовать триггеры для распределения нагрузки во времени.

Сторонние сервисы: Для сложных задач можно использовать внешние API или платформы (например, Cloud Functions), вызываемые из GAS, которые могут иметь более гибкие лимиты.

Сохранение полученного изображения в Google Drive

Получение доступа к Google Drive с использованием DriveApp

Сервис DriveApp предоставляет интерфейс для взаимодействия с файлами и папками на Google Drive пользователя или общем диске. Он позволяет создавать, искать, изменять и удалять файлы и папки.

Для сохранения изображения, полученного как Blob с помощью UrlFetchApp, используется метод createFile(blob).

Пример кода: Сохранение Blob-объекта изображения в Google Drive

/**
 * Сохраняет Blob-объект как файл в указанную папку Google Drive.
 *
 * @param {GoogleAppsScript.Base.Blob} imageBlob Blob-объект изображения.
 * @param {string} fileName Имя файла для сохранения.
 * @param {string} [folderId] ID папки для сохранения (опционально, по умолчанию - корневая папка).
 * @return {GoogleAppsScript.Drive.File | null} Объект сохраненного файла или null в случае ошибки.
 */
function saveBlobToDrive(imageBlob: GoogleAppsScript.Base.Blob, fileName: string, folderId?: string): GoogleAppsScript.Drive.File | null {
  try {
    let targetFolder: GoogleAppsScript.Drive.Folder;

    if (folderId) {
      try {
        targetFolder = DriveApp.getFolderById(folderId);
      } catch (e) {
        Logger.log(`Не удалось найти папку с ID: ${folderId}. Сохранение в корневую папку.`);
        targetFolder = DriveApp.getRootFolder();
      }
    } else {
      targetFolder = DriveApp.getRootFolder();
    }

    // Устанавливаем имя файла для Blob перед сохранением
    const namedBlob = imageBlob.setName(fileName);
    const file = targetFolder.createFile(namedBlob);
    Logger.log(`Файл '${fileName}' успешно сохранен в папку '${targetFolder.getName()}'. ID файла: ${file.getId()}`);
    return file;

  } catch (error) {
    Logger.log(`Ошибка сохранения файла '${fileName}' в Google Drive: ${error}`);
    return null;
  }
}

// Пример использования:
function testSaveImageToDrive() {
  const sampleImageUrl = 'https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png';
  const blob = fetchImageAsBlob(sampleImageUrl);

  if (blob) {
    // Генерируем имя файла (например, на основе URL или текущей даты)
    const timestamp = new Date().toISOString().replace(/[:.-]/g, '');
    const filename = `image_${timestamp}.png`; // Пытаемся угадать расширение или берем из Content-Type
    
    // Можно указать ID конкретной папки
    // const targetFolderId = 'YOUR_FOLDER_ID'; 
    // saveBlobToDrive(blob, filename, targetFolderId);
    
    saveBlobToDrive(blob, filename); 
  }
}
Реклама

Управление именами файлов и папками

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

Уникальные имена: Генерируйте уникальные имена, например, добавляя временную метку или хэш URL.

Расширение файла: Пытайтесь определить правильное расширение файла на основе MIME-типа (blob.getContentType()) или URL.

Структура папок: Используйте DriveApp.getFolderById() или DriveApp.createFolder() для организации файлов в определенных папках. Проверяйте существование папки перед использованием.

Обработка дубликатов: Перед созданием файла можно проверить, не существует ли уже файл с таким именем в целевой папке (folder.getFilesByName(fileName)), и решить, перезаписывать его или создавать новый с уникальным именем.

Использование полученного изображения в Google Sheets или Docs

Вставка изображения в Google Sheets: пример кода

Полученный Blob можно вставить непосредственно в ячейку Google Sheets.

/**
 * Вставляет изображение (Blob) в указанную ячейку Google Sheets.
 *
 * @param {GoogleAppsScript.Base.BlobSource} imageBlobSource Blob или файл Drive с изображением.
 * @param {string} sheetName Имя листа.
 * @param {string} cellNotation Обозначение ячейки (например, 'A1').
 * @param {number} [offsetX] Смещение по X внутри ячейки (опционально).
 * @param {number} [offsetY] Смещение по Y внутри ячейки (опционально).
 */
function insertImageIntoSheet(imageBlobSource: GoogleAppsScript.Base.BlobSource, sheetName: string, cellNotation: string, offsetX: number = 0, offsetY: number = 0): void {
  try {
    const ss = SpreadsheetApp.getActiveSpreadsheet();
    const sheet = ss.getSheetByName(sheetName);

    if (!sheet) {
      Logger.log(`Лист с именем '${sheetName}' не найден.`);
      return;
    }

    const cell = sheet.getRange(cellNotation);
    // Удаляем предыдущее изображение в ячейке, если оно есть
    sheet.getImages().forEach(img => {
      if (img.getAnchorCell().getA1Notation() === cellNotation) {
        img.remove();
      }
    });

    // Вставляем новое изображение
    const image = sheet.insertImage(imageBlobSource, cell.getColumn(), cell.getRow(), offsetX, offsetY);
    Logger.log(`Изображение успешно вставлено в ячейку ${cellNotation} листа '${sheetName}'.`);
    
    // Дополнительно: можно настроить размер изображения
    // image.setWidth(100); 
    // image.setHeight(50);

  } catch (error) {
    Logger.log(`Ошибка вставки изображения в Google Sheets: ${error}`);
  }
}

// Пример использования:
function testInsertImageIntoSheet() {
  const sampleImageUrl = 'https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png';
  const blob = fetchImageAsBlob(sampleImageUrl);
  if (blob) {
    insertImageIntoSheet(blob, 'Лист1', 'C3'); // Вставить в ячейку C3 на Лист1
  }
}

Вставка изображения в Google Docs: пример кода

Аналогично, Blob можно вставить в Google Docs.

/**
 * Вставляет изображение (Blob) в конец документа Google Docs.
 *
 * @param {GoogleAppsScript.Base.BlobSource} imageBlobSource Blob или файл Drive с изображением.
 * @param {string} [documentId] ID документа (опционально, по умолчанию - активный документ).
 */
function insertImageIntoDoc(imageBlobSource: GoogleAppsScript.Base.BlobSource, documentId?: string): void {
  try {
    let doc: GoogleAppsScript.Document.Document;
    if (documentId) {
      doc = DocumentApp.openById(documentId);
    } else {
      doc = DocumentApp.getActiveDocument();
    }

    const body = doc.getBody();
    // Вставляем изображение в конец документа
    const image = body.appendImage(imageBlobSource);
    Logger.log(`Изображение успешно вставлено в документ ID: ${doc.getId()}.`);

    // Дополнительно: можно настроить размер изображения
    // const width = image.getWidth();
    // const height = image.getHeight();
    // image.setWidth(width / 2).setHeight(height / 2); // Уменьшить в 2 раза

  } catch (error) {
    Logger.log(`Ошибка вставки изображения в Google Docs: ${error}`);
  }
}

// Пример использования:
function testInsertImageIntoDoc() {
  const sampleImageUrl = 'https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png';
  const blob = fetchImageAsBlob(sampleImageUrl);
  if (blob) {
    insertImageIntoDoc(blob); // Вставить в активный документ
    // const targetDocId = 'YOUR_DOCUMENT_ID';
    // insertImageIntoDoc(blob, targetDocId); // Вставить в документ по ID
  }
}

Настройка размеров и положения изображения

После вставки изображения как в Sheets (sheet.insertImage), так и в Docs (body.appendImage или paragraph.appendInlineImage), возвращается объект OverGridImage (Sheets) или InlineImage (Docs). Эти объекты предоставляют методы для управления размерами и, в некоторой степени, положением.

Google Sheets: OverGridImage позволяет установить смещение (offsetX, offsetY) при вставке. После вставки можно изменять ширину (setWidth) и высоту (setHeight). Изображение привязано к ячейке (getAnchorCell).

Google Docs: InlineImage позволяет изменять ширину (setWidth) и высоту (setHeight). Положение определяется местом вставки в тексте документа.

Заключение и оптимизация

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

Кэширование: Если один и тот же URL изображения используется многократно, сохраните Blob на Google Drive и используйте DriveApp.getFileById(id).getBlob() вместо повторной загрузки через UrlFetchApp.

Асинхронность: Для массовой обработки рассмотрите возможность использования триггеров или разделения задачи на части, чтобы не превышать лимиты времени выполнения.

Обработка ошибок: Всегда включайте надежную обработку ошибок для UrlFetchApp и операций с файлами/документами.

Размер изображений: Если возможно, используйте URL изображений с оптимальным размером, чтобы уменьшить время загрузки и объем данных.

Очистка: Удаляйте временные или ненужные файлы изображений с Google Drive, если они больше не требуются.

Альтернативные подходы и библиотеки (если применимо)

В рамках стандартного Google Apps Script сервис UrlFetchApp является основным и наиболее прямым способом получения данных по URL, включая изображения. Для специфических задач, таких как обработка изображений (изменение размера до вставки, наложение водяных знаков), могут потребоваться более сложные решения:

Google Cloud Functions: Можно создать функцию в Google Cloud, которая будет обрабатывать изображение (используя библиотеки типа sharp или ImageMagick), а затем вызывать эту функцию из GAS через UrlFetchApp.

Сторонние API: Существуют API для обработки изображений, которые можно вызывать из GAS.

Возможные проблемы и их решения

Превышение квот UrlFetchApp: Распределяйте запросы во времени, используйте кэширование.

Блокировка запросов сервером: Некоторые сайты могут блокировать запросы от Google. Попробуйте добавить User-Agent в заголовки запроса, но это не всегда помогает.

Неверный MIME-тип: response.getBlob() может вернуть Blob с неправильным или неопределенным типом контента. Проверяйте blob.getContentType() и при необходимости корректируйте расширение файла.

Ошибки авторизации: Убедитесь, что скрипту предоставлены все необходимые разрешения.

Дополнительные ресурсы и ссылки

Для дальнейшего изучения рекомендуется обратиться к официальной документации Google Apps Script:

Документация по UrlFetchApp.

Документация по DriveApp.

Документация по SpreadsheetApp и DocumentApp.

Обзор квот и ограничений Google Apps Script.

Изучение примеров на форумах сообщества и Stack Overflow также может быть полезным для решения конкретных задач и нестандартных задач.


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