×

Google Apps Script и с чем его едят

Россия +7 (909) 261-97-71
Шрифт:
0 316
Подпишитесь на нас в Telegram

Всем привет! Я Леша Штанько, системный администратор и интегратор (а иногда еще и JS-разработчик) в AGIMA.

Если представить экосистему Google как айсберг, то наверху окажутся Google Sheets, Calendar и другие популярные сервисы. А вот Google Apps Script остается в тени, хотя он невероятно полезен.

Эта статья – для тех, кто о нем еще не слышал. Я расскажу, как работает сервис, в чем его преимущества, и приведу практические примеры использования.

Несмотря на популярность Google-продуктов, в России мало кто использует Apps Script. А ведь он бесплатен и может серьезно упростить многие процессы.

В конце статьи будут ссылки на полезные ресурсы, если захотите изучить инструмент глубже.

Что такое Google Apps Script и на чем он работает

Apps Script – платформа на основе JavaScript для быстрой и простой разработки бизнес-решений. Apps Script привязан к конкретной версии JavaScript (ES5). Но чтобы можно было использовать современный синтаксис и функции JavaScript, в Apps Script была добавлена поддержка среды V8, которая, в свою очередь, поддерживает Chrome и Node.js.

Apps Script включает в себя следующие сервисы:

  1. DocumentApp – для работы с Google Docs.

  2. GmailApp – для работы с Gmail.

  3. SlidesApp – для работы с Google Slides.

  4. SpreadsheetApp – для работы с Google Sheets.

  5. FormApp – для работы с Google Form.

В статье мы коснемся сервиса SpreadsheetApp для работы с Google Sheets.

Сразу к делу. Фишки Apps Script

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

У нас в AGIMA есть огромный «ящик» разных инструментов, мы можем настроить под себя любые системы и заставить их работать так, как нам нужно. И при этом изобилии мы активно используем автоматизированные таблички Google Sheets.

Все наши внутренние команды имеют как минимум одну автоматизированную табличку. Например, для команд – это рентабельность по проекту с учетом трека времени, данных из Битрикса, подрядчиков и самого руководителя проекта.

Еще наш финотдел активно использует автоматизированные таблички: специалисты следят за расхождениями между затратами, за сроками выплат и актуальностью статусов по документам и т. д. Так 50–100 строчек кода ежедневно экономят нам по 2–3 часа на другие более приоритетные задачи.

Но вы можете подумать: «Пффф… И это все? Одна табличка?!» А вот и нет! Благодаря Google Apps Script вы можете дружить между собой столько табличек, сколько вам необходимо. И я сейчас говорю не про листы, а про отдельные файлы даже на других аккаунтах.

И это еще не все. Благодаря API мы можем тянуть данные из любых систем по обращению, а после – конвертировать их, как нам удобно.

Подробнее про API

К примеру, благодаря API-запросам мы тянем данные из нашего таск-трекера и Bitrix и интегрируем их в наши любимые таблички. Вот пример API-запроса в формате JS:

Здесь нет проверок на ошибки, чтобы этот фрагмент кода не превратился в крупный блок.

/** Функция обращения к таск трекеру по API */

function taskTrackerAuth() {

const sourceUrl =

'https://your_taskTracker_url/rest/tempo-timesheets/4/worklogs/search';

const options = {

'headers': { 'Authorization': 'Basic *******************' },

'method': 'post',

'contentType': 'application/json',

'Accept': 'application/json',

/** Полезная нагрузка настраивается индивидуально, то, что указано тут, можно очистить */

'payload': JSON.stringify({'from': [],'to': [], 'worker': [], 'projectKey': [], 'taskKey': [], 'filterId': [] }),

}

const taskTrackerResponse = UrlFetchApp.fetch(sourceUrl, options);

const data = JSON.parse(taskTrackerResponse.getContentText());

//Вывод сообщения о получении данных

if (data.length > 0) {

SpreadsheetApp.getActiveSpreadsheet().toast('Данные Timesheets получены', '(V)_O_o_(V)', 2);

} else {

SpreadsheetApp.getActiveSpreadsheet().toast('Данные Timesheets не получены', '(V)_O_o_(V)', 2);

}

}


Этот запрос обращен на получение данных из таск-трекера. Если его немного переделать, можно получить запрос и в другие системы, и выудить данные через API откуда угодно.

Пример работы с Apps Script

На этом я покончу с духотой. Можем перейти к живым примерам. Рассмотрим несложный пример работы с Apps Script, который сможет повторить любой человек даже без знания программирования. Все, что вам потребуется, – это всеми любимая комбинация ctrl-C ctrl-V.

Подготовка

Создадим документ Google Sheets у себя на диске Google Drive.

Google Sheets

И назовем его, как вам угодно. В моем случае – это файл Demo Habr:

Google Sheets

Далее мы открываем файл и идем в режим редактирования Apps Script. В верхней графе ищем пункт «Расширения» и в выпавшем меню находим заветную строчку Apps Script.

Apps Script

И попадаем в зазеркалье :)

Apps Script

На самом деле мы попали в редактор кода. Здесь и начинается вся магия.

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

Итак, создаю второй документ Google Sheets и заполняю его рандомными данными:

Apps Script

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

В первом документе Импорт данных.

Во втором документе Данные.

Далее пишем этот код в редакторе кода первой таблицы.

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

/** Функция получения данных */

function getData() {

/** Сокращение */

const ss = SpreadsheetApp.getActiveSpreadsheet();

/** ID документа, с которого будем забирать данные */

const sheetId = '1AxL1WddtqlanF-WwkpF-2qTj3V1NCHc2xRzVLF7v3ho';

/** Имя листа, с которого будем забирать данные */

const exportSheetName = 'Данные';

/** Имя листа на который будем вставлять данные */

let importSheetName = 'Импорт данных';

/** Проверка на корректность ID страницы */

try {

SpreadsheetApp.openById(sheetId);

} catch (e){

ss.toast('Ошибка в ID страницы', '(V)_O_o_(V)', 4);

}

/** Открываем таблицу с указанным идентификатором */

const openSheet = SpreadsheetApp.openById(sheetId);

/** Открываем лист с указанным именем */

const openList = openSheet.getSheetByName(exportSheetName);

/** Проверка на существование листа, с которого забираем данные */

try {

openList.getDataRange().getValues();

} catch (e){

ss.toast('Экспорт: Страницы с таким именем не существует', '(V)_O_o_(V)', 4);

}

/** Забираем данные с листа */

const data = openList.getDataRange().getValues();

/** Небольшая проверка на существование данных */

if (Object.values(data) != 0) {

/** Выведем сообщение о получении данных */

ss.toast('Данные получены', '(V)_O_o_(V)', 4);

/** Если такой лист уже есть, то создадим другой*/

if (ss.getSheetByName(importSheetName) != 0) {

/** Зафиксируем текущее время */

let todayDate = new Date (Date.now());

/** Если лист с таким именем уже есть, то добавляем ему в название old + текущее время */

SpreadsheetApp.getActive().getSheetByName(importSheetName).setName(importSheetName + " old " + todayDate.toUTCString());

/** Создаем свежий лист */

ss.insertSheet().setName(importSheetName);

} else {

/** Создаем свежий лист, если такого не было до этого */

ss.insertSheet().setName(importSheetName);

}

/** Импортируем данные на страницу */

ss.getSheetByName(importSheetName).getRange(1, 1, data.length, data[0].length).setValues(data);

/** Выведем сообщение о вставке данных */

ss.toast('Данные вставлены на лист', '(V)_O_o_(V)', 4);

} else {

/** Выведем сообщение об отсутствии данных */

ss.toast('Эх.. А данных то нет', '(V)_O_o_(V)', 4);

};

}

/** Функция очистки листа */

function clearList() {

/** Сокращение */

const ss = SpreadsheetApp.getActiveSpreadsheet();

/** Имя листа, который будем очищать */

const clearListName = 'Импорт данных';

/** Выделим лист, с которым будем работать */

const clearSheet = ss.getSheetByName(clearListName);

/** Подсчитаем количество всех строк на листе */

const maxRowsCount = clearSheet.getMaxRows();

/** Подсчитаем количество всех столбцов на листе */

const maxColumnsCount = clearSheet.getMaxColumns();

/** Очистим весь лист */

clearSheet.getRange(1, 1, maxRowsCount, maxColumnsCount).clear({ contentsOnly: true }); // Позволяет после очистки перезаписывать контент

/** Выведем сообщение об отсутствии данных */

ss.toast('Лист очищен', '(V)_O_o_(V)', 4)

};

/** Функция отображения выпадающего списка с кнопками в интерфейсе Google Sheets */

function onOpen() {

let ui = SpreadsheetApp.getUi();

ui.createMenu('Печеньки тут')

.addItem('Загрузить данные', 'getData')

.addItem('Очистить данные', 'clearList')

.addToUi();

}


В этом коде представлены три функции:

  1. getData() – функция получения всех данных из другого документа.

  2. clearList() – функция очистки листа от любых данных, которые находятся в нем.

  3. onOpen() – функция вызова дополнительного меню в интерфейсе самой таблички.

И четыре параметра, которые вам нужно будет поменять, чтобы все сработало.

Первый параметр:

const sheetId = '1AxL1WddtqlanF-WwkpF-2qTj3V1NCHc2xRzVLF7v3ho';


Тут нужно поменять id страницы. Проще всего его взять из url самой станицы. Здесь id я выделил жирным шрифтом:

https://docs.google.com/spreadsheets/d/1AxL1WddtqlanF-WwkpF-2qTj3V1NCHc2xRzVLF7v3ho/edit#gid=0

Копируете id и вставляете в ваш код.

  • Важно! Нужно вставить id страницы, с которой вы хотите забрать данные.

Второй параметр:

const exportSheetName = 'Данные';


Сюда вводите название листа, из которого хотите забрать данные. По дефолту это будет Лист 1.

Третий параметр:

const importSheetName = 'Импорт данных';

}


Сюда вводите название листа, на который хотите вставить данные. По дефолту это будет Лист 1.

Четвертый параметр:

const clearListName = 'Импорт данных';


Сюда вводите название страницы, которую хотите очистить от данных. Название должно быть такое же, как в третьем параметре.

Обязательно соблюдайте кавычки. Без них ничего работать не будет :)

В коде я разместил проверки. Если вы где-нибудь допустите ошибку, то получите сообщение с пояснением, где именно ошибка.

  • Данный код имитирует функцию IMPORTRANGE() в Google Sheets.

Запускаем код

С основными функциями закончили. Но теперь главный вопрос. Как запустить код? Для этого есть несколько способов:

1. В редакторе выбираем функцию getData() и нажимаем выполнить:

Apps Script

2. В главном интерфейсе находим пункт «Печеньки тут»:

Apps Script

Наведя на этот блок, вы получите выпадашку с двумя пунктами:

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

  2. Очистить лист.
    Стираете все данные с листа.

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

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

Если вдруг вы получили ошибку, то проверьте внимательно, правильно ли вы выполнили все шаги и не упустили ли что-то.

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

Почему Apps Script, а не обычные функции Google Sheets

Все очень просто! Ни одна из дефолтных функций Google Sheet не позволяет получать данные из закрытых авторизацией систем, а также миксовать данные между собой перед импортом. В какой-то момент мы начали упираться в то, что стандартные функции не могут стабильно переварить очень большие объемы данных. Особенно это касалось импорта данных. Для IMPORTRANGE() это ограничение составляет всего 10 Мб.

Вот пример:

Apps Script

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

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

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

Поэтому симбиоз стандартных функций и немного скриптологии дают впечатляющие результаты. Но одно не отменяет другого: что-то удобнее сделать посредством кода, а что-то внутренними функциями. Так сказать, берем лучшее из обоих миров.

Пример архитектуры, которую мы выстроили с помощью Google Sheets

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

Apps Script

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

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

Благодаря такой системе мы можем получать и обрабатывать данные за полгода и более. Если вдруг где-то закралась ошибка, то она будет отображаться в таблице пользователя или буферной таблице. Согласитесь, ведь получается быстрее и эффективнее, когда ты точно знаешь, где ошибка, а не тратишь полдня на поиск разногласия.

Apps Script

Одна из сложностей, для которой есть решение

Если даже взять тот пример, который мы сделали в рамках этой статьи, и просто скопировать, то вы продублируете и код, который прикреплен к таблице. Звучит неплохо. Но тут есть одно очень жирное но! Если вы внесете изменение в код в одном документе, то код во втором документе останется без изменений.

Чтобы упростить взаимодействие пользователей с табличками, мы создаем универсальное решение для всех. У нас есть шаблон той или иной таблички, пользователь скачивает ее, вводит свои данные для авторизации (да, именно так, никаких захардкорженных данных для входа внутри кода) и начинает ей пользоваться.

Таким образом у нас получается 40–50 дублей этой таблички, которые работают независимо друг от друга.

При обновлениях функциональности, по идее, нам нужно брать ноги в руки, бегать по всем табличкам и вносить изменения вручную. Но тут нам на помощь приходят библиотеки! Библиотека в Apps Script выглядит как отдельный файл с кодом, который подключается к табличкам в меню редактирования кода. Из дополнительных плюсов этого решения – можно быть уверенным, что никто туда лишний раз не залезет и не наворошит там своими очумелыми ручками :)

У нас не раз были истории, когда приходит сотрудник и просит о помощи: «Хелп, ахтунг, алерт, у меня ничего не работает!». И ты с лицом лягушки Пепе бежишь смотреть, что же там произошло.

Пепе

Выясняется, что сотрудник уже пытался починить все самостоятельно, и случайно удалил часть кода. Чтобы избежать такой проблемы мы используем библиотеки.

Из плюсов:

  1. Основной код лежит подальше от любопытных глаз и рук. Нельзя пофиксить то, что ты не видишь :)

  2. Изменения в главном файле применяются ко всем документам, к которым прикреплена эта библиотека.

  3. Становится легче определить ошибку кода или локальную ошибку.

Из минусов: на самом деле пользователи могут редактировать библиотеку, но для этого им нужно вытащить ссылку на скрипт.

Библиотека

Заключение

Во многих странах люди платят большие деньги за настройку автоматизированных табличек для сбора метрик даже из социальных сетей. Надеюсь, что такие статьи, как эта, смогут исправить ситуацию с незаслуженной непопулярностью Apps Script у нас.

Материалов по обучению работе с Apps Script и его кодом очень много на зарубежных сайтах. А еще есть примеры в открытых репозиториях на GitHub.

Как и обещал, оставлю тут полезные ссылочки на материалы:

  1. Туториал от самого Google: https://developers.google.com/apps-script?hl=ru

  2. Описание методов Apps Script для Google Sheets: https://developers.google.com/apps-script/reference/spreadsheet?hl=ru

Оригинал статьи на SEOnews

Есть о чем рассказать? Тогда присылайте свои материалы в редакцию.


Новые 
Новые
Лучшие
Старые
Сообщество
Подписаться 
Подписаться на дискуссию:
E-mail:
ОК
Вы подписаны на комментарии
Ошибка. Пожалуйста, попробуйте ещё раз.
Отправить отзыв
ПОПУЛЯРНЫЕ ОБСУЖДЕНИЯ НА SEONEWS
Роскомнадзор начал требовать от владельцев сайтов уведомлять об использовании Google Analytics. Опыт SEOnews
Денис Добрынин
1
комментарий
0
читателей
Полный профиль
Денис Добрынин - Что-то я как-то пропустил момент, с которого например госномер автомобиля или разрешение монитора и версия установленного на ПК ОС стала перс.данными... Но сегодня тоже получили бумажку с ай-яй-яем. Пойдем на прием в теруправление.
Что такое AIO (AI Optimization) или GEO-оптимизация, как быть на шаг впереди конкурентов
Эдуард
1
комментарий
0
читателей
Полный профиль
Эдуард - Годно) многие моменты я не знал.
Количество пользователей ИИ в сервисах Mail превысило 5 млн человек
Сергей Карененко
1
комментарий
0
читателей
Полный профиль
Сергей Карененко - Поздравление еще худо бедно написать можно. А когда в почте больше 10к писем, вот тут хорошо, что ии есть)
В Почте и Облаке Mail появился новый тариф – «Семейный»
Анна Макарова
393
комментария
0
читателей
Полный профиль
Анна Макарова - Да, конечно, владелец видит все файлы. А про других пользователей так написано: подключившие этот тариф, могут добавлять в подписку до 4 пользователей. Всем, кого пригласили в подписку, предоставляется доступ к терабайту облачного пространства для общих дел.
Россиянам могут запретить рекламу в Instagram* и Facebook*
Марина Ибушева
66
комментариев
0
читателей
Полный профиль
Марина Ибушева - Окончательное как раз и означает третье. Любой законопроект перед тем, как отправиться в Совет Федерации и на подпись прзиденту, проходит в России три обязательные стадии рассмотрения в Государственной Думе: Первое чтение - обсуждается общая концепция законопроекта. Второе чтение - более детальное обсуждение проекта, поправки и дополнения. Третье чтение (окончательное) - голосование за проект. Так что ожидается 25 марта второе и третье, окончательное чтение.
Фиды, фильтры, внутренний поиск: как выжать максимум при технических ограничениях и увеличить трафик более чем в 5 раз
i-Media интернет-агентство
2
комментария
0
читателей
Полный профиль
i-Media интернет-агентство - Google Merchant работает, товары показываются - в кейсе есть скриншот с примером.
AI SEO в 2025: 5 шагов к видимости бренда в поиске нового поколения
Пиксель Плюс
1
комментарий
0
читателей
Полный профиль
Пиксель Плюс - Сергей, здравствуйте! Мы починили ссылку. Спасибо, что обратили внимание!
Целевая аудитория: как найти и встроиться в ее вселенную
Александра
2
комментария
0
читателей
Полный профиль
Александра - Здравствуйте! Благодарю Вас за отличную статью! Много полезной информации, написано доступным языком.
5 цифровых инструментов для офлайн-бизнеса. Как привести клиента в торговую точку
Гость
1
комментарий
0
читателей
Полный профиль
Гость - Полезно! Спасибо
Главные апдейты Google 2024: что изменилось и как продвигать сайты в 2025 году
Старый сеошник
5
комментариев
0
читателей
Полный профиль
Старый сеошник - Ребята, ну серьёзно? Это исследование и итоги?) Просто везде: усиливает борьбу, улучшение контента, улучшение ссылок и т.д. А что нового? А где конкретика, цифры, динамика? Или итог: В 2025 году продвижение сайтов должно опираться на качество контента и улучшение пользовательского опыта. Браво, ради этого стоило писать статью) Информативность 0. Возразите мне?
ТОП КОММЕНТАТОРОВ
Комментариев
910
Комментариев
834
Комментариев
554
Комментариев
540
Комментариев
483
Комментариев
393
Комментариев
373
Комментариев
262
Комментариев
249
Комментариев
171
Комментариев
156
Комментариев
141
Комментариев
124
Комментариев
121
Комментариев
100
Комментариев
97
Комментариев
97
Комментариев
96
Комментариев
80
Комментариев
77
Комментариев
74
Комментариев
67
Комментариев
66
Комментариев
60
Комментариев
59

Отправьте отзыв!
Отправьте отзыв!