Python

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

Подготовка к работе

1. Установите библиотеки

Мы будем использовать google-cloud-bigquery для получения данных из Google BigQuery. matplotlib, numpy и pandas помогут нам с визуализацией данных. python-telegram-bot будет отправлять изображения с визуализацией в чат Telegram.

pip3 install google-cloud-bigquery matplotlib numpy pandas python-telegram-bot

2. Включите Google BigQuery API

Для начала нужно включить API Google BigQuery.

Перейдите в Google Developers Console и создайте новый проект (или выберите существующий).

В панели управления проектом выберите “Обзор API”, нажмите “Включить API и сервисы” и найдите BigQuery API.

Нажмите “Включить”, чтобы включить данный API. 

3. Создайте ключ сервисного аккаунта

Если мы хотим использовать такие облачные сервисы Google, как Google BigQuery, нам нужен ключ сервисного аккаунта.

Перейдите в Google Developers Console, нажмите “Обзор API”, затем перейдите во вкладку “Учетные данные”, нажмите “Создать учетные данные” и “Ключ сервисного аккаунта”.

Во вкладке “Сервисный аккаунт” нажмите “Новый сервисный аккаунт” и введите имя в поле “Название сервисного аккаунта”.

Из выпадающего списка во вкладке “Роль” выберите вариант Проект-Владелец. Далее нажмите “Создать”.

На ваш компьютер будет автоматически загружен .json файл. Назовите его creds.json.

В терминале для GOOGLE_APPLICATION_CREDENTIALS пропишите путь к нашему creds.json файлу.

export GOOGLE_APPLICATION_CREDENTIALS='[PATH_TO_CREDS.JSON]'

Все готово, пора приступать к написанию нашего приложения.

Написание приложения

Мы собираемся написать приложение, которое будет запрашивать данные из BigQuery (в данном примере мы предполагаем, что данные хранятся там). Далее мы визуализируем данные и сохраним их в виде изображения. На последнем этапе изображение будет отправлено через чат в Telegram.

В этой статье мы воспользуемся данными из bigquery-public-data.stackoverflow и установим количество ежедневных публикаций для нашего отчета.

Последовательность действий нашей программы довольно проста:

Запрашиваем данные из таблицы-> Визуализируем данные-> Сохраняем визуализированные данные в виде изображения -> Отправляем изображение

1. Query к BigQuery

Сначала импортируем библиотеку.

from google.cloud import bigquery

Затем создадим функцию query_to_bigquery, которая будет использовать query в качестве параметра.

def query_to_bigquery(query):
client = bigquery.Client()
query_job = client.query(query)
result = query_job.result()
dataframe = result.to_dataframe()
return dataframe

Эта функция вернет данные в виде датафрейма.

2. Визуализируем данные

Мы будем использовать matplotlib для визуализации данных.

import matplotlib.pyplot as plt

Нам нужно пять параметров: x — данные по оси х, x_label— имя метки по оси x, y — данные по оси y, y_label — имя метки по оси y и title — заголовок визуализации. 

def visualize_bar_chart(x, x_label, y, y_label, title):
plt.title(title)
plt.xlabel(x_label)
plt.ylabel(y_label)
index = np.arange(len(x))
plt.xticks(index, x, fontsize=5, rotation=30)
plt.bar(index, y)
return plt

3. Сохраняем изображение

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

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

query = """ 
SELECT DATE(creation_date) date, COUNT(*) total_posts
FROM `bigquery-public-data.stackoverflow.post_history`
GROUP BY 1
HAVING date > DATE_SUB('2018-12-02', INTERVAL 14 DAY)
ORDER BY 1
"""

Обратите внимание, что в приведенном выше запросе HAVING date > DATE_SUB('2018-12-02', INTERVAL 14 DAY) означает, что мы хотим собрать данные за две недели, начиная со 2 декабря 2018 года.

Мы используем эту дату, потому что 2018-12-02 — это последние данные, записанные в bigquery-public-data.stackoverflow.post_history. В других случаях вы можете использовать CURRENT_DATE(), чтобы получить новейшие данные.

Вызовите функцию query_to_bigquery для получения данных.

dataframe = query_to_bigquery(query)

Возьмите столбец date в качестве данных по оси x, и столбец total_posts в качестве данных по оси y.

x = dataframe['date'].tolist()
y = dataframe['total_posts'].tolist()

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

plt = visualize_bar_chart(x=x, x_label='Date', y=y, y_label='Total Posts', title='Daily Posts')
plt.savefig('viz.png')

Оберните этот код в функцию get_and_save_image.

def get_and_save_image():
query = """
SELECT DATE(creation_date) date, COUNT(*) total_posts
FROM `bigquery-public-data.stackoverflow.post_history`
GROUP BY 1
HAVING date > DATE_SUB('2018-12-02', INTERVAL 14 DAY)
ORDER BY 1
"""
dataframe = query_to_bigquery(query)
x = dataframe['date'].tolist()
y = dataframe['total_posts'].tolist()
plt = visualize_bar_chart(x=x, x_label='Date', y=y, y_label='Total Posts', title='Daily Posts')
plt.savefig('viz.png')

4. Отправляем изображение

Чтобы убедиться, что изображение попадет к тому, кому нужно, нам необходимо знать параметр chat_id.

Найдите в Telegram бот userinfobot и нажмите “Start”. Бот пришлет информацию о пользователе, где номер в поле Id— это и есть chat_id

Создайте функцию send_image. Сначала данная функция вызовет функцию get_and_save_image, чтобы получить и сохранить визуализацию, а затем отправит ее человеку, чей chat_id объявлен в переменной chat_id.

def send_image(bot, update):
get_and_save_image()
chat_id = 'CHAT_ID_RECEIVER'
bot.send_photo(chat_id=chat_id, photo=open('viz.png','rb'))

5. Основное приложение

Наконец, создайте функцию main для запуска нашего приложения. Не забудьте изменить YOUR_TOKEN для токена вашего бота.

Запомните: это приложение будет автоматически отправлять изображения в указанное вами время.

Например, мы установили время на 9:00 ежедневно.

def main():
    updater = Updater('YOUR_TOKEN')
    updater.job_queue.run_daily(send_image, time=datetime.datetime.strptime('9:00AM', '%I:%M%p').time(), days=(0,1,2,3,4,5,6))
    updater.start_polling()
    updater.idle()

 
if __name__ == '__main__':
    main() 

В итоге ваш код должен выглядеть так:

from google.cloud import bigquery
from telegram.ext import Updater

import matplotlib.pyplot as plt
import numpy as np
import datetime

def query_to_bigquery(query):
client = bigquery.Client()
query_job = client.query(query)
result = query_job.result()
dataframe = result.to_dataframe()
return dataframe

def visualize_bar_chart(x, x_label, y, y_label, title):
plt.title(title)
plt.xlabel(x_label)
plt.ylabel(y_label)
index = np.arange(len(x))
plt.xticks(index, x, fontsize=5, rotation=30)
plt.bar(index, y)
return plt

def get_and_save_image():
query = """
SELECT DATE(creation_date) date, COUNT(*) total_posts
FROM `bigquery-public-data.stackoverflow.post_history`
GROUP BY 1
HAVING date > DATE_SUB('2018-12-02', INTERVAL 14 DAY)
ORDER BY 1
"""
dataframe = query_to_bigquery(query)
x = dataframe['date'].tolist()
y = dataframe['total_posts'].tolist()
plt = visualize_bar_chart(x=x, x_label='Date', y=y, y_label='Total Posts', title='Daily Posts')
plt.savefig('viz.png')

def send_image(bot, update):
get_and_save_image()
chat_id = 'CHAT_ID_RECEIVER'
bot.send_photo(chat_id=chat_id, photo=open('viz.png', 'rb'))

def main():
updater = Updater('YOUR_TOKEN')
updater.job_queue.run_daily(send_image, time=datetime.datetime.strptime('9:00AM', '%I:%M%p').time(), days=(0,1,2,3,4,5,6))
updater.start_polling()
updater.idle()

if __name__ == '__main__':
main()

Сохраните файл и назовите его main.py.

Запустите приложение, введя в терминале команду:

python3 main.py

Замечательно! Теперь у вас есть бот, автоматически генерирующий отчеты, созданный с помощью 50 строчек кода. Довольно круто, не правда ли?

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

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

Вы можете посетить мой GitHub, чтобы получить готовый код.

Перевод статьи Dzaky Widya Putra: How to build a bot to automate your mindless tasks using Python and Google BigQuery