Мини-гайд по отправке сообщений из Google Таблицы или базы данных с Python

от автора

В этом материале расскажем, как автоматизировать отправку сообщений-уведомлений по данным из таблицы.

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

Основная идея работы заключается в том, чтобы связать базу данных с формой SMS-рассылки. Она, в свою очередь, использует API Exolve для отправки ранее заготовленного сообщения. Для упрощения задачи мы расскажем про реализацию проекта с применением Google Таблиц, но благодаря одному из наших прошлых гайдов можно легко произвести привязку к CMS.

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

Именно поэтому алгоритм работы будет следующий:

  1. Создать Excel-файл со всей необходимой информацией (имя, адрес, номер телефона, номер заказа).

  2. Создать форму для автоматической отправки сообщений (с автоматической подстановкой данных, кодом авторизации).

  3. Сделать привязку Excel-файла к форме для автоматической передачи данных каждые 20 секунд.

  4. Profit.

Это решение может показаться немного «костыльным» из-за формы — без нее можно обойтись, автоматизировав чтение и отправку сообщений.

Для того, чтобы система работала в автоматическом режиме, потребуется сервер. Нагрузка не очень большая, можно использовать даже просто рабочий ноутбук — из требований к серверу можно выделить только go 1.20, наличие SSL (https), а также маршрутизацию.

Этап 1. Создание Excel-файла

Лучший вариант — воспользоваться онлайн-системой по типу Google Docs. Это потребует постоянного подключения к интернету или общей сети, но гарантирует практически моментальный отклик при необходимости.

Из обязательных полей можно выделить:

  • номер получателя;

  • имя покупателя;

  • текст для рассылки («Ваш заказ номер НН готов»);

  • адрес получения («подойдите туда-то»);

  • номер отправителя (если внутри Exolve арендовали несколько номеров для разных филиалов, например).

Итоговый вариант таблицы может выглядеть следующим образом:

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

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

import asyncio import json import requests as requests from google.oauth2 import service_account from googleapiclient.discovery import build async def send_message_client(data):     url = 'https://api.exolve.ru/messaging/v1/SendSMS'     # для сайта     response = requests.post(url=url, headers={         "Authorization": "”Код авторизации”",     }, json=data)     print(type(response.json))     print(response.json)     print(response)     return response class GoogleSheetData:     def __init__(self):         # Путь к файлу JSON с учетными данными         self.SERVICE_ACCOUNT_FILE = 'credentials.json'         # Создание учетных данных из файла JSON         self.creds = service_account.Credentials.from_service_account_file(             self.SERVICE_ACCOUNT_FILE,             scopes=[                 'https://www.googleapis.com/auth/spreadsheets',                 'https://www.googleapis.com/auth/drive',             ]         )         # Создание клиента API         self.service = build('sheets', 'v4', credentials=self.creds)         # ID вашей таблицы Google Sheets         self.spreadsheet_id = 'ID'     async def processing_google_sheet(self):         try:             # открываем файл JSON, читаем данные и записываем их в переменную 'data'             # если файл не найден, создаем новую пустую переменную 'data'             try:                 with open('data.json', "r") as file:                     data = json.load(file)             except FileNotFoundError:                 data = {1: ['Имя', 'Ваш заказ номер НН готов', 'подойдите туда-то', 'Номер']}             # получаем номер строки с которым будем работать             row = int(list(data.keys())[0]) + 1             # Запрос на получение данных из таблицы Google Sheets(получаем определенную строку в range)             response = self.service.spreadsheets().values().get(                 spreadsheetId=self.spreadsheet_id,                 range=f"Лист1!A{row}:E{row}",             ).execute()             # получаем строку с данными             values = response.get('values', [])             print(values)             # проверяем на наличие данных             if not values:                 print('No data found.')             elif len(values[0]) >= 5 and '' not in values[0]:                 data_excel = {"number": values[0][4], "destination": values[0][0], "text": f"{values[0][1]}, Ваш заказ номер {values[0][2]} готов, подойдите {values[0][3]}"}                 print(data_excel)                 result_send_message = await send_message_client(data_excel)                 data = {row: values[0]}                 print(data)                 # записываем новые данные в файл 'data.json'                 with open('data.json', "w") as file:                     json.dump(data, file, indent=4, ensure_ascii=False)         except Exception as e:             print(f"An error occurred: {e}") async def run_processing_google_sheet(google_sheet_req):     while True:         await google_sheet_req.processing_google_sheet()         await asyncio.sleep(20) if __name__ == "__main__":     google_sheet_req = GoogleSheetData()     asyncio.run(run_processing_google_sheet(google_sheet_req))

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

Этап 2. Создание формы отправки

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

В первую очередь займемся написанием кода обработки, а после дополним его внешней составляющей — кстати, кастомизировать ее можно по своему усмотрению и даже включить в пользовательский интерфейс.

Для удобства дальнейшего использования мы написали код работы формы на Python. Остается вставить его в любой компилятор и сохранить в виде отдельного файла:

import asyncio import json import re import requests as requests from google.oauth2 import service_account from googleapiclient.discovery import build from quart import Quart, render_template, request  app = Quart(__name__) async def send_message_client(data):     url = 'https://api.exolve.ru/messaging/v1/SendSMS'     # для сайта     response = requests.post(url=url, headers={         "Authorization": "Код авторизации",     }, json=data)     return response @app.route('/', methods=['GET', 'POST']) def index():     if request.method == 'POST':         data = dict(request.form)         for key in request.form:             if request.form[key] == '':                 return render_template('index.html', error='Не все поля заполнены!')             if key == 'destination':                 if not re.match('7\d{9}', request.form[key]):                     return render_template('index.html', error='Неправильный формат номера телефона')         result_send_message = send_message_client(data)         if "error" in result_send_message.json:             return render_template('index.html', error=f"Ошибка, вид ошибки: {result_send_message.json()}")         return render_template('index.html', error=f"Запрос обработан!, id message: {result_send_message.json()}")     return render_template('index.html') if __name__ == "__main__":     app.run()

Этот код, помимо отправки сообщений, еще может проверять поля на корректность заполнения — правильно ли указан номер телефона, например. В остальном же это потребует параллельного запуска с основным табличным файлом.

Формируем файл JavaScript, в котором распишем, что должна делать эта форма: в частности, получать значения в специальные поля и передавать их в API Exolve:

async function postData(formProps) {   const url = 'https://api.exolve.ru/messaging/v1/SendSMS';   const data = { number: number, destination: destination, text: text };    try {     console.log(JSON.stringify(data));     const response = await fetch(url, {       method: "POST",       body: JSON.stringify(formProps),       headers: {         "Authorization": "Код авторизации",       },     });     const json = await response.json();     console.log("Успех:", JSON.stringify(json));   } catch (error) {     console.error("Ошибка:", error);   } } function logSubmit(event) {   event.preventDefault();   const formData = new FormData(event.target);   const formProps = Object.fromEntries(formData);   postData(formProps); } const form = document.getElementById("form"); form.addEventListener("submit", logSubmit);

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

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

Рабочий, но не очень эстетичный момент, не так ли? Последний шаг — добавить визуальную составляющую — стиль в CSS.

*, *::before, *::after {   margin: 0;   padding: 0;   box-sizing: border-box; } body {   min-height: 100vh;   padding: 50px;   display: flex;   align-items: center;   justify-content: center;   background-color: #18191c;   color: #FFFFFF;   font-family: 'Kanit', sans-serif;   font-family: 'Roboto', sans-serif;   font-size: 18px; } h4 {     color: red;     margin-bottom: 2vh; } input, textarea{   width: 100%;   padding: 12px;   margin-bottom: 25px;   border: 1px solid #ccc;   border-radius: 4px;   box-sizing: border-box;   resize: vertical; } label {   display: flex;   align-items: center;   justify-content: space-between;   margin-bottom: 25px; } .input, .button {   width: 350px; } .input {   border: 1px solid #ffffff;   border-radius: 6px;   padding: 10px 15px;   background-color: transparent;   color: #ffffff;   font-family: inherit;   font-size: inherit;   font-weight: 300;   -webkit-appearance: none;   appearance: none; } .input:focus {   border-color: #FFD829;   outline: none; } .button {   display: block;   min-width: 210px;   border: 2px solid transparent;   border-radius: 6px;   margin-left: auto;   padding: 9px 15px;   color: #000000;   font-size: 18px;   font-weight: 300;   font-family: inherit;   transition: background-color 0.2s linear; } .button:hover {   background-color: #FF0032;   cursor: pointer;   transition: background-color 0.2s linear; } .button:focus-visible {   border: 2px solid #ffffff;   outline: none; } .button:focus {   border: 2px solid #ffffff;   outline: none; } .button-yellow {   background-color: #FFD829; } .button:disabled {   opacity: 0.5;   cursor: not-allowed; } .hidden {   display:none; } @media (max-width: 768px) {   body {     padding: 30px;   }   label {     display: block;   }   .input, .button {     display: block;     width: 100%;   } }

Для того, чтобы получить доступ к форме, нужно вручную запустить сайт — потребуется подключение к Интернету, а также запущенный ранее созданный нами файл. При желании можно «вшить» код в пользовательский интерфейс, а также настроить.

Этап 3. Настройка

Чтобы все работало корректно и не требовало доработок, необходимо дополнительно создать файл настройки с актуализацией версий используемых библиотек:

aiofiles==23.2.1 anyio==4.1.0 beautifulsoup4==4.12.2 blinker==1.7.0 cachetools==5.3.2 certifi==2023.11.17 charset-normalizer==3.3.2 click==8.1.7 Flask==3.0.0 google==3.0.0 google-api-core==2.15.0 google-api-python-client==2.111.0 google-auth==2.25.2 google-auth-httplib2==0.2.0 google-auth-oauthlib==1.2.0 googleapis-common-protos==1.62.0 greenlet==3.0.2 h11==0.14.0 h2==4.1.0 hpack==4.0.0 httpcore==1.0.2 httplib2==0.22.0 httpx==0.25.2 Hypercorn==0.15.0 hyperframe==6.0.1 idna==3.6 itsdangerous==2.1.2 Jinja2==3.1.2 MarkupSafe==2.1.3 oauth2client==4.1.3 oauthlib==3.2.2 priority==2.0.0 protobuf==4.25.1 pyasn1==0.5.1 pyasn1-modules==0.3.0 pyparsing==3.1.1 python-telegram-bot==20.7 Quart==0.19.4 requests==2.31.0 requests-oauthlib==1.3.1 rsa==4.9 six==1.16.0 sniffio==1.3.0 soupsieve==2.5 SQLAlchemy==2.0.17 typing_extensions==4.9.0 uritemplate==4.1.1 urllib3==2.1.0 Werkzeug==3.0.1 wsproto==1.2.0

Для всех желающих оставляем ссылку на готовый код в GitHub с полной сборкой и всеми составляющими.

Работу алгоритма можно представить следующим образом: сотрудник заполняет соответствующую форму (создается автоматически для рабочего интерфейса или с помощью Google Форм), которая передает данные в общую таблицу. Возможно также ручное заполнение — например, если нужно вносить правки в уже созданные заявки.

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

Последний шаг — непосредственная работа API Exolve для отправки сообщения на указанный номер телефона. В коде уже прописаны автоматические комментарии к полям («подойдите туда-то»), их можно изменить самостоятельно. Как итог — покупатели получат следующие сообщения:

Мы повторимся, что этот код можно упростить, автоматизировав его и убрав форму — то есть, передавать данные напрямую в API. Но в таком случае исключается возможность ручного воздействия — изменения данных и отправки сообщений «вне очереди». 


ссылка на оригинал статьи https://habr.com/ru/articles/842106/


Комментарии

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *