Сохранение данных из форм в Google Таблицы
Google Tаблицы — это сервис, который позволяет создавать, обновлять и редактировать таблицы и делиться данными онлайн. Если вы выбираете Google Таблицы в качестве сервиса приема данных из форм, то информация, которую заполнят посетители на сайте, автоматически запишется в таблицу и у вас будет доступ к ней через ваш аккаунт Google.
1. У вас должен быть аккаунт на Google. Если аккаунта нет, зарегистрируйтесь.
2. Перейдите на Тильду. Настройки сайта → Формы → Google Таблицы (Google Sheets)
На следующем экране нажмите кнопку «Подключить Google Sheets». Нажмите на нее, приложение попросит разрешить доступ к вашему аккаунту на Google. После разрешения, будет создана новая таблица на Google Диске в папке Tilda Leads, в нее после настройки будут попадать данные из форм.

Если все прошло успешно, то вы автоматически вернетесь на страницу настроек интеграции. Вы можете указать другое название файла с таблицей и создать новую папку для таблицы внутри созданной папки Tilda Leads на Google Диске.

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

Если вы хотите включить сервис на определенных страницах сайта, перейдите в редактирование страницы, где расположена форма, откройте меню «Контент» блока с формой и поставьте галочку напротив сервиса приема данных Google Таблицы.

Опубликуйте страницу. При получении данных из форм, в Google Таблице автоматически создадутся поля в том же порядке, что и в вашей форме, например: email, name, phone. По умолчанию добавится время отправки, ID запроса и ссылка на страницу, с которой пришли данные.
Создание Google Формы с выводом результатов в Google Таблицы

Многие знают о существовании онлайн-сервиса под названием Google Формы. Это средство для создания опросов, анкет и различных тестов, которые можно распространять в сети и собирать ответы. Полученные результаты выводятся непосредственно в веб-сервисе Форм, однако у создателя есть возможность реализовать сбор ответов в Таблицы, чтобы управлять ими, создавать сводки и реализовывать другие задачи. Как раз об этом я и расскажу в рамках данной статьи.
Создание Google Формы
Начать нужно непосредственно с создания Google Формы. Для этого вам понадобится пустая таблица, в которую и будут приниматься все ответы в будущем. Процесс ее создания разбирать не буду, а вот организацию связи с формой покажу.
- После перехода к новой таблице вызовите меню «Инструменты» и щелкните по кнопке «Создать форму».

- Откроется новая вкладка, где вы можете изменить название для формы и добавить ее описание.

- После этого заполните поле первого вопроса и выберите тип ответа.

- В меню доступно много вариантов тестирования. Этот материал не посвящен разбору всех этих инструментов, поэтому опустим их описание.

- После выбора одного из вопросов заполните варианты ответов или другие параметры, отобразившиеся ниже.

- Можете открыть меню «Настройки темы», чтобы выбрать основной цвет, добавить изображение для колонтитула, поменять шрифт и цвет фона.

- По завершении настройки переходите к отправке опроса.

- Поддерживаются три типа распространения формы: личная рассылка по адресам электронной почты, ссылка для перехода и встраиваемый на сайт HTML-код. Выберите удобный для вас вариант отправки.

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

- Далее отвечает на вопросы и нажимает на кнопку «Отправить». После этого появится уведомление о том, что ответы записаны.

- Теперь в связанной таблице появляется новый лист с названием «Ответы на форму (1)». Откройте его для просмотра содержимого.

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

- Таблица автоматически обновляется после поступления новых ответов, а вам остается только изучить полученную информацию.

Соответственно, само оформление таблицы зависит исключительно от того, как вы создали Форму, собираете ли личные данные юзеров, сколько вопросов создали и так далее. В этом плане переживать не стоит, ведь вы обязательно увидите все полученные от пользователей сведения.
Управление Google Формой через Google Таблицу
В завершение рассмотрим некоторые полезные моменты, которые могут пригодиться при управлении формой через созданную Таблицу. Во-первых, через то же самое меню «Инструменты» вы можете вызвать «Управление формой». Там есть кнопки для перехода к изменению формы, открытию ее для просмотра, быстрое средство отправки и опция для удаления связи, если больше не нужно получать ответы.
![]()
Во-вторых, присутствует полезная кнопка «Показать сводку ответов», при нажатии по которой вы направляетесь на страницу формы и видите список предоставленных личных данных и диаграмм, отображающих ответы. Так у вас получится очень быстро узнать, какие варианты ответов выбирались чаще.
![]()
Если ваша форма еще не связана с Google Таблицей или вы потеряли этот документ, на вкладке «Ответы» щелкните по значку таблицы для ее открытия в новой вкладке. Ответы либо будут сформированы с нуля, либо вы получите доступ к своему старому листу, который создавали по инструкции выше.
![]()
Подобный сбор информации через электронную таблицу будет полезен в разных областях, где используется тестирование и анкетирование. Вы всегда будете в курсе последних изменений, сможете создавать любые сводные таблицы, фильтровать и сортировать данные в соответствии со своими потребностями.
Все возможности Google Forms
Елена Соловьева, менеджер проектов в Лаборатории Касперского, специально для блога Нетологии написала статью о том, как использовать Google Forms по максимуму.
Google Формы — онлайн-сервис для создания форм обратной связи, онлайн-тестирований и опросов. Инструмент популярный, но весь спектр его возможностей используется редко. В статье я расскажу, когда и для чего пригодятся Google Формы и как максимально эффективно их применять.
Польза Google Форм
Каждая форма в Google Формах представляет собой веб-страницу, на которой размещается анкета или квиз. Все, что нужно для работы с формами, — это иметь аккаунт в Google.
Что можно сделать с помощью Google Форм
- онлайн-регистрацию на мероприятие;
- онлайн-исследование;
- сбор фидбека;
- бриф;
- голосование и т. д.
Чем удобны Google Формы
- Простота в использовании. Работать с Google Формами не сложнее, чем с MS Word. Интерфейс удобный и понятный. Форму не надо скачивать, пересылать своим клиентам и получать от них по почте заполненный вариант.
- Доступность 24/7. Форма хранится в облаке. Если вы работаете с разных устройств или ваш жесткий диск повредился, форма останется доступна при наличии ссылки.
- Индивидуальное оформление. Вы можете создать свой дизайн для формы. Google Формы дают возможность бесплатно выбрать шаблон из большого количества доступных или загрузить свой.
- Бесплатность. Сам сервис бесплатный. Заплатить придется только в случае, если вам вдруг понадобится расширенный вариант дополнительных надстроек.
- Мобильность. Google Формы адаптированы под мобильные устройства. Создавать, просматривать, редактировать и пересылать формы можно с телефона и планшета с помощью облегченной мобильной с полной функциональностью.
- Понятность. Google Формы собирают и профессионально оформляют статистику по ответам. Вам не придется дополнительно обрабатывать полученные данные, можно сразу приступать к анализу результатов.
Как правильно настроить этот инструмент, чтобы извлечь из него максимум? Я подготовила несколько пошаговых рекомендаций.
Настройте форму
Начните с основных настроек, которые задают параметры и технические характеристики формы.
С помощью верхней панели настраивается поведение формы:
- Дополнения.
- Внешний вид.
- Предпросмотр.
- Настройки.
- Кнопка отправки.
- Действия с формой.
Дополнения. Кликните левой кнопкой мыши по иконке. Здесь появятся дополнения к форме, которые вы настроите. Отсюда же дополнения запускаются:


Внешний вид. Вы можете выбрать однотонную заливку формы или воспользоваться каталогом тем. Чтобы открыть каталог, кликните левой кнопкой мыши на иконку иллюстрации. Выберете любую (некоторые анимированы) или загрузите свою. Тема задает шапку формы и фон.

Предпросмотр. Кликните левой кнопкой мыши на иконку глаза, чтобы посмотреть, как ваши адресаты увидят форму. Эта кнопка пригодится в конце формирования опроса.
Настройка. Кликните левой кнопкой мыши на иконку шестеренки и задайте параметры формы.
- Закладка «Общие». Здесь интересен пункт «Отправлять форму не более одного раза». Он полезен тем, кто использует форму для исследований. Отметьте этот пункт, чтобы избежать заполнение форм ботами или искусственной нагонки показателей. Google Формы идентифицируют пользователя по Google аккаунту и не разрешают отвечать на опрос более одного раза с одного аккаунта. Я собираюсь делать тест, поэтому отметила этот параметр.

Чтобы собирать адреса электронной почты тестируемых, отметьте параметр «Собирать адреса электронной почты». Его активация автоматически добавляет обязательное поле «Электронный адрес» в начале формы.
- Закладка «Презентация». Укажите, что и как будут видеть ваши адресаты.

- Закладка «Тесты». Если цель создания формы — провести тестирование, передвиньте ползунок в закладке «Тесты», чтобы активировать нужные опции. Активация включает дополнительные настройки, доступные при создании формы: вы сможете назначать количество баллов на вопрос и автоматически оценивать прохождение теста каждым участником. Чтобы дать быстрый фидбек тестируемому, отметьте «Показать оценку сразу после отправки формы».

Кнопка «Отправить». Нажав на нее, вы можете выбрать способ и параметры отправки. Форма отправляется по почте, ссылкой на форму, через встраиваемый код или соцсети. При отправке по почте есть возможность включить форму в тело сообщения. Ваш адресат сможет заполнить опрос не переходя по внешним ссылкам сразу из письма. К сожалению, такая опция хорошо работает только с Gmail. С другими почтовыми сервисами эта функция работает некорректно.

Действия с формой. Кликните левой кнопкой мыши на иконку после кнопки отправки, чтобы раскрыть меню действий с формой. Форму можно удалить, копировать, распечатать. Это же меню позволяет создать из формы предзаполненный шаблон, подключить дополнения и настроить доступ.


ЕЛЕНА СОЛОВЬЕВА

курс
Основы веб‑аналитики для интернет-маркетологов
Узнать больше
- Получите базовые знания по веб-аналитике и разберётесь, подходит ли вам эта сфера
- На практике поймёте, как с помощью данных принимать эффективные решения для бизнеса
- Изучите кейсы работы с данными и самостоятельно попрактикуетесь
Создайте форму
После того, как вы определились с форматом, настройкой и поведением опроса, раздали права доступа и задали дизайн, можно переходить к созданию самой формы. Сначала продумайте структуру опроса на бумаге, чтобы потом не запутаться в логике в конструкторе.
Конструктор
Первые два поля появились по умолчанию: заголовок формы и электронный адрес (обязательное поле по умолчанию, если вы активировали параметр «Собирать адреса электронной почты»).
Начнем создавать новые поля. Если в продуманной вами логике тест получился очень длинным, разбейте его на разделы и добавьте иллюстрации.
Переходим в панель конструктора справа. Для добавления раздела кликните на нижнюю иконку. Чтобы вставить дополнительный материал, например картинки, видео или текстовое описание, кликните на соответствующую иконку.

Google Формы разрешают загружать картинки прямо с устройства, Google диска, Google поиска, через ссылку или с камеры. Видео подтягиваются из Ютуба.
Чтобы вставить вопрос нажмите на «+» в верху панели. Введите название вопроса (это может быть картинка — кликните на иконку иллюстрации, чтобы ее вставить) и выберете тип вопроса из раскрывающегося меню справа.
Типы вопросов:
Текст (строка). Этот тип вопроса предполагает короткий ответ. Его удобно использовать, когда вы хотите получить email, имя, адрес, цифровое значение, ссылку. В этом типе вопроса доступны функции:
- Функция «Описание» доступна во всех типах. Чтобы ее активировать, нажмите на значок в правом нижнем углу и отметьте параметр «Описание».
- Функция «Проверка ответов». Чтобы ее активировать, кликните на иконку в правом нижнем углу. В области настройки появится нужная строка. Вы можете задать параметры для текста, который будет вводить тестируемый. К примеру, мне важно, чтобы ответ был не более 50 символов. Если в поле будет введено больше символов, респондент получит заданное сообщение «Слишком длинный ответ». Если он справится с условием, то получит 4 балла.
Если вы хотите, чтобы в строку было введено число, выберете из выпадающего меню параметр «Число» вместо «Длина» и установите нужные характеристики:
Таким же образом можно выбрать и настроить параметр «Текст» и «Регулярное выражение»:
- Функция «Ответы». Чтобы задать количество баллов для вопроса кликните на синюю надпись «Ответы» и задайте необходимые параметры в открывшемся окне. Чтобы вернуться к настройкам вопроса, нажмите на синюю надпись «Изменить вопрос» внизу.
- Для всех типов вопросов доступны функции копирования (удобно, если нужно создать несколько однотипных вопросов), удаления и перевод в обязательный режим (в этом режим вопрос обозначается звездочкой, а тестируемый не может отправить форму без ответа на него). Перечисленные функции включаются с нижней панели настройки вопроса.
Текст (абзац). Этот тип вопроса предполагает развернутый ответ. Его удобно использовать при запросе развернутого фидбека. Все функции и настройки совпадают с типом вопроса «Текст (строка)»:
- «Описание»;
- «Проверка ответов». Для этого типа вопросов доступна настройка только 2 параметров «Длина» и «Регулярное выражение»;
- «Задать количество баллов»;
- Копирование, удаление, «Обязательный вопрос».
Один из списка. Этот тип вопроса предполагает выбор одного варианта из предложенных. Его удобно использовать в качестве разводящего по логике формы — в зависимости от выбранного варианта тестируемого перебрасывают на другие разделы или в конец формы. Рассмотрим, как это сделать.
Здесь доступны функции:
- «Описание».
- «Задать количество баллов».
- Копирование, удаление, «Обязательный вопрос».
- «Выбрать действие для каждого ответа». Чтобы активировать эту функцию, кликните на иконку в правом нижнем углу и отметьте нужный пункт. Вы можете задать желаемое действие для каждого варианта ответа. Когда тестируемый отметит одну из опций, форма выполнит указанное к этой опции действие. Здесь нам пригодится разделение на разделы — из выпадающего списка действий выбираем «Перейти к следующему разделу» или указываем, к какой секции нужно перейти. К примеру, в моем тесте есть вопрос типа «Один из списка» на использование английского времени Present Perfect. При правильном ответе на этот вопрос я перевожу респондента сразу во вторую секцию, указав это в настройках верного ответа. На этом этапе я уже понимаю, что человек владеет темой. Если тестируемый ответил неверно, то он идет дальше по вопросам первой секции о Present Perfect.
- «Перемешать строки». Каждый раз при открытии формы ответы на вопрос будут перемешиваться.
- «Задать правильный ответ». Нажмите на синюю надпись «Ответы» внизу, отметьте верный ответ и задайте количество баллов, которое получит тестируемый при выборе правильного ответа. Чтобы перейти обратно к настройкам вопроса нажмите на синюю надпись «Изменить вопрос» внизу. В настройках вопроса верный ответ будет выделен зеленой галочкой.
Несколько из списка. Этот тип вопроса предполагает выбор нескольких вариантов ответа из предложенных.

- «Описание»,
- Копирование, удаление, «Обязательный вопрос»,
- «Задать правильный ответ»,
- «Задать количество баллов»,
- «Перемешать строки»,
- «Проверка ответов». Для ее активации, как и в вопросе типа «Текст (строка)», кликните на иконку в правом нижнем углу. В появившейся строке задайте количество правильных ответов и текст сообщения, который появится, если тестируемый выберет больше или меньше опций.
Раскрывающийся список. Этот тип вопроса предполагает выбор одного варианта ответа из раскрывающегося списка. Такие вопросы более компактные, чем «Один из списка». Раскрывающийся список удобен, если нужно дать большое количество опций. Его можно использовать в качестве разводящего, так как он позволяет настроить переход на другие разделы или завершить заполнение формы досрочно.
- «Описание»,
- «Задать количество баллов»,
- Копирование, удаление, «Обязательный вопрос»,
- «Выбрать действие для каждого ответа»,
- «Перемешать строки»,
- «Задать правильный ответ».
Шкала. Этот тип вопроса предполагает оценку показателя по предложенной шкале.
- «Описание»,
- «Задать количество баллов»,
- Копирование, удаление, «Обязательный вопрос»,
- «Задать шкалу». Кликните на стрелочки под описанием и выберете из выпадающего меню, сколько уровней будет у ответа. Ниже укажите максимальное и минимальное значение шкалы. Их можно задать и через эмоджи
Сетка (множественный выбор). Этот тип вопроса предполагает оценку нескольких единиц по предложенной шкале.
- «Описание»,
- «Задать количество баллов»,
- Копирование, удаление, «Обязательный вопрос»,
- «Перемешать строки»,
- «По одному ответу на столбец». Кликните на иконку в правом нижнем меню и активируйте функцию. Тестируемый сможет выбрать только одно значение в каждом столбце.
Сетка флажков. Этот тип вопроса предполагает оценку параметров по нескольким критериям.
- «Описание»,
- «Задать количество баллов»,
- Копирование, удаление, «Обязательный вопрос»,
- «Перемешать строки»,
- «По одному ответу на столбец».
Дата. Этот тип вопроса предполагает выбор даты из календаря.
- «Описание»,
- «Задать количество баллов»,
- Копирование, удаление, «Обязательный вопрос»,
- «Добавить время». Кликните на иконку в правом нижнем углу и установите флажок напротив этой функции для активации. Появится дополнительное поле для ввода конкретного времени для выбранной даты.
- «Добавить год».Кликните на иконку в правом нижнем углу и установите флажок напротив этой функции для активации. Появится дополнительное поле для ввода года для выбранной даты.
Время. Этот тип вопроса предполагает введение конкретного времени. Его удобно использовать при почасовом бронировании ресурсов.
- «Описание»,
- «Задать количество баллов»,
- Копирование, удаление, «Обязательный вопрос»,
- «Время» и «Продолжительность». Это взаимоисключающие функции. Кликните на иконку в правом нижнем углу и установите флажок напротив нужной функции для активации. Выбрав одну из них, установите, что будет означать введенное время: время начала действия или его продолжительность.
Предзаполненный шаблон
Бывает удобно отправить сразу предзаполненную форму, чтобы клиент делал корректировки, но не заносил всю информацию. Для этого в настройках выберите «Создать образец заполнения» и заполните форму. Нажмите «Ответить». Google Формы создадут ссылку для предзаполненной формы, по которой респонденты будут корректировать данные, а не заполнять с нуля.

Дайте доступ респондентам
После создания и настройки формы дайте доступ респондентам. Для этого перейдите в настройки и выберите «Настройки доступа».
- Прямая ссылка на форму,
- Возможность поделиться ссылкой в соцсетях,
- Настройка уровней доступа для тех, у кого есть ссылка.
После того, как доступ настроен, нажмите кнопку «Отправить» на верхней панеле. Еще раз проверьте настройки отправки и разошлите форму.
Проанализируйте результаты
После отправки над формой появляются две вкладки «Вопросы» и «Ответы». Кликните на последнюю.
Здесь будет отображаться статистика по всем присланным ответам. Переключая табы, можно просмотреть:
- Общую сводку по ответам,
- Статистику пользователей по конкретному ответу,
- Ответы отдельного респондента.
В любой момент можно передвинуть ползунок «Принимать ответы» и деактивировать функцию. После этого никто не сможет отправить ответы к форме.
Для более подробного анализа удобно собирать ответы в таблице. Для этого нажмите на зеленую иконку . Данные в таблицу собираются в режиме реального времени — респондент отправляет ответ, который автоматически фиксируется в таблице. Вы также можете скачать ее в формате csv. Для этого кликните на значок и выберете нужную опцию.
Из раскрывшегося меню также настраиваются две полезные функции:
- «Получать уведомления о новых ответах по электронной почте». Эта функция позволяет быстро реагировать. Она удобна, если количество респондентов небольшое.
- «Удалить связь с формой». Эта функция полезна, если вы случайно удалили ответы из таблицы. Прервите и затем восстановите связь с формой — все ответы снова подтянутся в таблицу.
Установите нужные дополнения
У Google Форм есть дополнения, которые облегчают работу, правда, их не так много, как у Google Docs. Чтобы их подключить, перейдите в настройки в верхней панели формы, кликните «Дополнения» и выберите нужное. После установки первого дополнения на верхней панеле настроек появится значок , при нажатии на который откроется список всех установленных add-ins. Рассмотрим самые, на мой взгляд, полезные.
Email Notifications for Forms позволяет настраивать email-уведомления при отправке формы. Можно задать кому, от кого, при каких условиях должно отправляться сообщение и что оно должно содержать. В сам текст письма можно добавить любой вопрос из формы, внеся его в скобки >, и прикрепить к нему ответы из формы в PDF-формате.
Экспорт Google Forms + загрузка Google Script через REST API (Python)

У нас было две гугл-формы, 75 вопросов в каждой, 5 бизнес-пользователей, которые активно правили эти формы, а еще гугл-скрипт, экспортирующий форму в JSON. Не то что бы его было сложно каждый раз запускать руками, но раз начал автоматизировать свою работу, то иди в этом увлечении до конца.
В официальной документации сам черт ногу сломит, поэтому под катом мы подробно рассмотрим удаленную загрузку и запуск Google Apps Script через REST API, используя Python.
Введение
У нас в «Доктор рядом» разрабатывается платформа для чат-ботов, в которой для описания сценариев используются гугл-формы. Соответственно, хочется из форм по нажатию кнопки получать JSON, содержащий ноды (пункты формы) и метаданные к ним (переходы между нодами, типы нод, их название). Казалось бы, желание простое, но гугл не поддерживает данный функционал и приходится собирать этот «экспортер» своими руками. Рассмотрим по шагам процесс его создания.
ШАГ 1. Google Apps Script
Google предусмотрел возможность взаимодействия со своими сервисами (Sheets, Docs, Forms) через Google Apps Script — скрипты, написанные на языке google script (.gs). Данная статья не предусматривает разбора языка google script, поэтому приведу пример готового скрипта, создающего JSON из имеющейся гугл-формы. За основу был взят с гитхаба код пользователя Steven Schmatz, за что выражаю ему свою благодарность.
Код скрипта
// Steven Schmatz // Humanitas Labs // 13 October, 2016. // Roman Shekhovtsov // dr-telemed.ru // Autumn 2019 // Nikita Orekhov // dr-telemed.ru // Autumn 2019 /** * Converts the given form URL into a JSON object. */ function main() < form_url var form = FormApp.openByUrl(form_url); var items = form.getItems(); var result = < "metadata": getFormMetadata(form), "items": items.map(itemToObject), "count": items.length >; // sendEmail("", result) return result; > /** If we want to receive data by email * Sends JSON as text to recipient email * @param recipient: String * @param result: JSON */ function sendEmail(recipient, json_file) < var subject = "google form json import" var body = JSON.stringify(json_file); Logger.log(body); MailApp.sendEmail(recipient, subject, body); >/** * Returns the form metadata object for the given Form object. * @param form: Form * @returns (Object) object of form metadata. */ function getFormMetadata(form) < return < "title": form.getTitle(), "id": form.getId(), "description": form.getDescription(), "publishedUrl": form.getPublishedUrl(), "editorEmails": form.getEditors().map(function(user) < return user.getEmail() >), "count": form.getItems().length, "confirmationMessage": form.getConfirmationMessage(), "customClosedFormMessage": form.getCustomClosedFormMessage() >; > /** * Returns an Object for a given Item. * @param item: Item * @returns (Object) object for the given item. */ function itemToObject(item) < var data = <>; data.type = item.getType().toString(); // Downcast items to access type-specific properties var itemTypeConstructorName = snakeCaseToCamelCase("AS_" + item.getType().toString() + "_ITEM"); var typedItem = item[itemTypeConstructorName](); // Keys with a prefix of "get" have "get" stripped var getKeysRaw = Object.keys(typedItem).filter(function(s) ); getKeysRaw.map(function(getKey) < var propName = getKey[3].toLowerCase() + getKey.substr(4); // Image data, choices, and type come in the form of objects / enums if (["image", "choices", "type", "alignment"].indexOf(propName) != -1) ; // Skip feedback-related keys if ("getFeedbackForIncorrect".equals(getKey) || "getFeedbackForCorrect".equals(getKey) || "getGeneralFeedback".equals(getKey)) ; var propValue = typedItem[getKey](); data[propName] = propValue; >); // Bool keys are included as-is var boolKeys = Object.keys(typedItem).filter(function(s) < return (s.indexOf("is") == 0) || (s.indexOf("has") == 0) || (s.indexOf("includes") == 0); >); boolKeys.map(function(boolKey) < var propName = boolKey; var propValue = typedItem[boolKey](); data[propName] = propValue; >); // Handle image data and list choices switch (item.getType()) < case FormApp.ItemType.LIST: case FormApp.ItemType.CHECKBOX: data.choices = typedItem.getChoices().map(function(choice) < return choice.getValue() >); case FormApp.ItemType.MULTIPLE_CHOICE: data.choices = typedItem.getChoices().map(function(choice) < gotoPage = choice.getGotoPage() if (gotoPage == null) return choice.getValue() else return < "value": choice.getValue(), "gotoPage":choice.getGotoPage().getId() >; >); break; case FormApp.ItemType.IMAGE: data.alignment = typedItem.getAlignment().toString(); if (item.getType() == FormApp.ItemType.VIDEO) < return; >var imageBlob = typedItem.getImage(); data.imageBlob = < "dataAsString": "", //imageBlob.getDataAsString(), - BLOB too big "name": imageBlob.getName(), "isGoogleType": imageBlob.isGoogleType() >; break; case FormApp.ItemType.PAGE_BREAK: data.pageNavigationType = typedItem.getPageNavigationType().toString(); break; default: break; > // Have to do this because for some reason Google Scripts API doesn't have a // native VIDEO type if (item.getType().toString() === "VIDEO") < data.alignment = typedItem.getAlignment().toString(); >return data; > /** * Converts a SNAKE_CASE string to a camelCase string. * @param s: string in snake_case * @returns (string) the camelCase version of that string */ function snakeCaseToCamelCase(s) < return s.toLowerCase().replace(/(\_\w)/g, function(m) ); >
Что происходит в коде:
- функция getFormMetadata — возвращает JSON с метаданными формы
- функция itemToObject — преобразует объект form.item в JSON с требуемыми полями
- функция sendEmail — отправляет текстом JSON файл на указанную почту
- функция main — возвращает итоговый JSON
- переменная form_url в функции main — адрес нашей гугл-формы
ШАГ 2. Тестирование скрипта
В данный момент работоспособность скрипта можно проверить следующим образом:
- создаем свой App Script проект
- копируем в него код
- вместо подставляем адрес своей формы вида docs.google.com/forms/d/FORM_IDENTIFICATOR/edit
- раскомментируем вызов функции sendEmail в функции main
- вместо подставляем адрес своей электронной почты, на которую хотим получить JSON
- сохраняем проект
- запускаем функцию main
- если это первый запуск скрипта, то система сообщит о необходимости дать скрипту разрешение отправлять email с вашего адреса. Не стоит пугаться. Это стандартная процедура, необходимая для тестирования скрипта. Проходим «Review permissions» -> выбираем свой аккаунт -> «Advanced» -> «Go to PROJECT_NAME project (unsafe)» -> «Allow»
- ждем отработки скрипта
- смотрим в почтовый ящик и видим JSON файл в текстовом виде
Внимание: Для удобства понимания происходящего, ниже я буду ссылаться только на две страницы, поэтому рекомендуется открыть их в соседних вкладках:
- Страница скриптов / редактирования скрипта — «страница 1»
- Страница Google Cloud Platform — «страница 2»
ШАГ 3. Настройка Google Cloud Platform
Заходим в Google Cloud Platform (страница 2), создаем новый проект. Необходимо создать новый проект, ибо по умолчанию статус проекта — Default, а для наших целей требуется Standart. Подробнее можно почитать тут (пункт 3).
Возвращаемся на страницу 2, переходим во вкладку «API и сервисы», затем «Окно запроса доступа OAuth». Ставим User Type «Внешний».
В появившемся окне заполняем «Название приложения».
Открываем главную страницу в Google Cloud Platform. Из блока «Информация о проекте» копируем номер проекта.
Переходим на страницу 1. Открываем ранее созданный скрипт. В открывшемся окне редактирования скрипта идем в «Resources» -> «Cloud Platform project». В поле «Change project» вводим скопированный ранее номер проекта. Теперь этот скрипт ассоциирован с созданным проектом.
ШАГ 4. Python REST API
Пришло время автоматизировать работу скрипта с помощью REST API. В качестве языка был использован Python.
Логин в Apps Script API
Код должен иметь доступ к проекту, поэтому первая и очень важная процедура — логин в Apps Script API. Открываем страницу 2 -> «API и сервисы» -> «Учетные данные» -> «Создать учетные данные» -> «Идентификатор клиента OAuth» -> «Другие типы». Называем наш идентификатор, переходим в него. Находясь во вкладке «Учетные данные», выбираем «Скачать файл JSON». При этом будет загружен файл ключей для доступа из кода к проекту в гугле. Помещаем данный файл в папку «credentials».
Теперь необходимо дать разрешение на использование API (в нашем случае Apps Script API) в рамках данного проекта. Для этого переходим в «API и сервисы» -> «Библиотека» -> набираем в поиске «Apps Script API» и нажимаем «Включить».
Приложения, взаимодействующие с гуглом, имеют скоп разрешений, которые пользователь должен дать при его запуске. Этот скоп зависит от функций, используемых конкретным скриптом и узнать его можно, пройдя на странице 1 в окне редактирования скрипта в «File» -> «Project Properties» -> «Scopes». Указанные разрешения следует сохранить для дальнейшего использования в коде.
В таком случае функция логина будет выглядеть следующим образом:
import pickle import os.path from googleapiclient.discovery import build from google_auth_oauthlib.flow import InstalledAppFlow from google.auth.transport.requests import Request def login(config): try: creds = None # The file token.pickle stores the user's access and refresh tokens, and is # created automatically when the authorization flow completes for the first # time. token_file = config['credentials_path'] + config['token_file'] credentials_file = config['credentials_path'] + config['credentials_file'] if os.path.exists(token_file): with open(token_file, 'rb') as token: creds = pickle.load(token) # If there are no (valid) credentials available, let the user log in. if not creds or not creds.valid: if creds and creds.expired and creds.refresh_token: creds.refresh(Request()) else: flow = InstalledAppFlow.from_client_secrets_file(credentials_file, config['SCOPES']) creds = flow.run_local_server(port=0) # Save the credentials for the next run with open(token_file, 'wb') as token: pickle.dump(creds, token) service = build('script', 'v1', credentials=creds) pprint('Login successful') return service except Exception as e: pprint(f'Login failure: ') return None
Данный блок кода — стандартная процедура для начала работы с Google App Script.
Мы используем аутентификационный токен и, осуществляя login, либо создаем новый токен, либо используем уже существующий.
Для удобства был создан конфигурационный JSON файл, имеющий следующий вид:
Важно: токен создается для аутентификации с конкретным скопом разрешений. Иными словами, при изменении скопа разрешений, следует удалить токен и при логине создать новый.
Удаленное обновление кода скрипта
Теперь научимся удаленно обновлять код скрипта, затем запускать этот код и получать результат. На самом деле, помимо того кода, что мы запускаем в гугловском редакторе, есть еще манифест файл, в котором указаны права запуска, настройки деплоймента и т.д. Подробнее ознакомиться с его структурой можно по ссылке.
Чтобы посмотреть на дефолтный манифест файл, созданный гуглом к вашему скрипту, пройдите в редакторе скрипта в «View» -> «Show manifest file». Манифест появится в списке файлов, относящихся к данному скрипту.
Речь о манифесте зашла неспроста: для удаленного обновления скрипта требуется загрузка кода обоих файлов (*.gs) и манифеста (appscript.json).
Для начала читаем код .gs файла, который мы хотим задеплоить:
with open('export-google-form.gs', 'r') as f: sample_code = f.read()
Теперь скопируем автоматически сгенерированный манифест и немного модифицируем его под наши цели. Документация достаточно исчерпывающе описывает структуру манифест файла, поэтому останавливаться на этом моменте я не буду. Для работы скрипта необходимо добавить в дефолтный манифест секцию «executionApi», которая требуется для удаленного запуска скрипта через API. В данной секции указываем круг лиц, имеющих возможность запускать его. Я разрешил запуск для всех, кто прошел авторизацию, что соответствует идентификатору «ANYONE»:
MANIFEST = ''' < "timeZone": "America/New_York", "exceptionLogging": "STACKDRIVER", "executionApi": < "access": "ANYONE" >> '''.strip()
Тело запроса на обновление должно содержать в себе массив файлов со следующей структурой:
- name: имя файла, который будет создан на сервере, без расширения
- type: тип файла (JSON для манифеста, SERVER_JS для .gs)
- source: код файла
request = < 'files': [< 'name': 'hello', 'type': 'SERVER_JS', 'source': sample_code >, < 'name': 'appsscript', 'type': 'JSON', 'source': MANIFEST >] >
Наконец, сам запрос на обновление должен содержать в себе тело (request, описанный выше) и ID скрипта. Последнее можно получить, пройдя в редакторе скрипта в «File» -> «Project Properties» и скопировав «Script ID»:
script_id = 'qwertyuiopQWERTYUIOPasdfghjkl123456789zxcvbnmASDFGHJKL54'
У объекта service, полученного в результате логина, получаем поле projects() и вызываем метод updateContent(), после чего у полученного объекта HttpRequest вызываем метод execute():
service.projects().updateContent( body=request, scriptId=script_id ).execute()
Однако, на данный момент запуск кода приведет к ошибке:
"error":
Как видим, не хватает разрешений в аутентификационном скопе, который мы указали ранее. Обратимся к официальной документации по API, а именно к методу updateContent, который мы использовали для удаленного обновления скрипта. Документация гласит, что использование этого метода требует включения разрешения доступа к script.projects:
https://www.googleapis.com/auth/script.projects
Добавим его в нашу конфигурационный файл в секцию SCOPES. Как я уже писал выше, при изменении скопа, необходимо удалять автоматически создающийся токен.
Отлично! На данный момент мы научились удаленно обновлять гугл скрипт. Осталось его запустить и получить результат выполнения.
Запуск скрипта
Запрос на запуск скрипта содержит scriptID и body со следующей структурой:
- function: имя функции, которую мы хотим запускать
- parameters: (optional) набор параметров примитивного типа (string, array . ), передаваемых в функцию
- sessionState: (optional) требуется только для Android приложений
- devMode: (optional) True в случае если юзер является владельцем скрипта и тогда будет запущена самая свежая версия, нежели та, что задеплоена с помощью Apps Script API. (по дефолту — False)
Внимание. Когда мы тестировали скрипт, то функция main ничего не принимала, поэтому изменим первые строки кода в .gs файле следующим образом:
function main(form_url) < var form = FormApp.openByUrl(form_url); .
Так как наше приложение не под Android и мы являемся владельцами скрипта, то в итоге body будет выглядеть так:
body =
Запустим скрипт и запишем результат выполнения в переменную resp:
resp = service.scripts().run(scriptId=script_id, body=body).execute()
Сохраним resp в файл с удобным JSON форматированием:
import json with open('habr_auto.json', 'w', encoding='utf-8') as f: json.dump(resp['response']['result'], f, ensure_ascii=False, indent=4)
Внимание. В силу того, что script.run() запрос ждет результат через сокет, то при превышении таймаута временем выполнения, произойдет ошибка следующего типа:
socket.timeout: The read operation timed out
Для избежания такого поведения, рекомендую в начале программы установить лимит на открытое время сокета, заведомо достаточное для того чтобы он дождался окончания выполнения скрипта. В моем случае 120 секунд достаточно:
import socket socket.setdefaulttimeout(120)
Вуаля! Удобный пайплайн для удаленного обновления и запуска гугл скриптов готов. Полный код, приспособленный к запуску из терминала приведен в моем гитхабе.
Также, приведу код основных функций ниже
login.py
from pprint import pprint import pickle import os.path from googleapiclient.discovery import build from google_auth_oauthlib.flow import InstalledAppFlow from google.auth.transport.requests import Request def login(config): try: creds = None # The file token.pickle stores the user's access and refresh tokens, and is # created automatically when the authorization flow completes for the first # time. token_file = config['credentials_path'] + config['token_file'] credentials_file = config['credentials_path'] + config['credentials_file'] if os.path.exists(token_file): with open(token_file, 'rb') as token: creds = pickle.load(token) # If there are no (valid) credentials available, let the user log in. if not creds or not creds.valid: if creds and creds.expired and creds.refresh_token: creds.refresh(Request()) else: flow = InstalledAppFlow.from_client_secrets_file(credentials_file, config['SCOPES']) creds = flow.run_local_server(port=0) # Save the credentials for the next run with open(token_file, 'wb') as token: pickle.dump(creds, token) service = build('script', 'v1', credentials=creds) pprint('Login successful') return service except Exception as e: pprint(f'Login failure: ') return None
update_script.py
from pprint import pprint import json import sys from googleapiclient import errors from google_habr_login import login MANIFEST = ''' < "timeZone": "America/New_York", "exceptionLogging": "STACKDRIVER", "executionApi": < "access": "ANYONE" >> '''.strip() def update_project(service, script_id, script_file_name): # Read from file code we want to deploy with open(script_file_name, 'r') as f: sample_code = f.read() # Upload two files to the project request = < 'files': [< 'name': 'hello', 'type': 'SERVER_JS', 'source': sample_code >, < 'name': 'appsscript', 'type': 'JSON', 'source': MANIFEST >] > # Update files in the project service.projects().updateContent( body=request, scriptId=script_id ).execute() pprint('Project was successfully updated') def main(): try: args = sys.argv if len(args) != 4: raise TypeError('Wrong number of arguments. Three argument required: , and ' '') config_file_name = args[1] script_id = args[2] script_file_name = args[3] with open(config_file_name, "r") as f: config = json.load(f) service = login(config) update_project(service, script_id, script_file_name) except (errors.HttpError, ) as error: # The API encountered a problem. pprint(error.content.decode('utf-8')) if __name__ == '__main__': main()
export_form.py
from pprint import pprint import socket import json import sys from googleapiclient import errors from google_habr_login import login socket.setdefaulttimeout(120) # Get JSON, which is returned by script def get_json(service, file_name, script_id, form_url): pprint('Exporting form. ') body = < "function": "main", "devMode": True, "parameters": form_url ># Get JSON from script resp = service.scripts().run(scriptId=script_id, body=body).execute() # Write out JSON to file with open(file_name, 'w', encoding='utf-8') as f: json.dump(resp['response']['result'], f, ensure_ascii=False, indent=4) pprint('Form was successfully exported') def main(): try: args = sys.argv if len(args) != 5: raise TypeError('Wrong number of arguments. Four arguments required: , ' ', and ') config_file_name = args[1] file_name = args[2] script_id = args[3] form_url = args[4] with open(config_file_name, "r") as f: config = json.load(f) service = login(config) get_json(service, file_name, script_id, form_url) except (errors.HttpError, ) as error: # The API encountered a problem. pprint(error.content.decode('utf-8')) if __name__ == '__main__': main()
Для запуска необходимо поместить JSON файл с ключами доступа к гуглу в папку «credentials», а конфигурационный JSON в одной директории со скриптами.
Затем, если мы хотим удаленно обновить скрипт, то в терминале вызвать:
python update_script.py
В данном случае:
- config_file_name — имя конфигурационного JSON файла
- script_id — ID скрипта
- script_file_name — имя .gs файла, который будет залит в гугл
python export_form.py
В данном случае:
- config_file_name — имя конфигурационного JSON файла
- result_file_name — имя JSON файла, в который будет выгружена форма
- script_id — ID скрипта
- google_form_url — URL гугл-формы
