Отправить результат SQL запроса через Telegram бота на Python. Обойти ограничение символов и привести в читаемый вид
Потребность:
- Автоматизировать работу, которая привязывает меня к компу в выходные =). Необходимо знать актуальное состояние данных в БД
Задача:
- Отправить в ТГ бота сообщение (предопределенное название селекта (СУБД - Postgres, Lib - psycopg2)) в ответ получить полный результат запроса
Описание сущностей: все таблицы, к которым будут обращаться селекты имеют вид:
- Дата актуальности(10 символов, char) PK is not null
- Код (2 символа, char) PK is not null
- Числовое значение 1 (до 7 символов, int)
- Числовое значение 2 (до 7 символов, int)
- Числовое значение 3 (до 7 символов, int)
- Таймстамп занесения данных в БД(19 символов, char) is not null
Проблемы с которыми столкнулся:
Ограничение по количеству символов, так как необходим полный результат селекта (в таблице порядка 40к кортежей). Так как селект с фильтрацией, возвращается порядка двухсот строк, но и этого достаточно, чтобы словить ошибку из-за ограничения. Хочется узнать как бы обходить такую проблему сохраняя целостность кортежей (просто сплитить по ограничению кол-ва знаков не получится, плюс есть некоторые проблемы с отправкой цельного списка через send_message(отправляет только самый первый элемент (первую дату)), поэтому приходится генерировать целевое сообщение циклом for:
cur.execute("select ... ") data = cur.fetchall() string_to_send = '' hop_count = 0 #Сделал счетчик строк для информативности for tuple in data: #Курсор возвращает список тьюплов for string_to_append in tuple: string_to_send += ' ' + str(none_case(string_to_append)) #Делаем из тьюпла строку. Функция none_case - преобразование None значений в строку "Null" string_to_send += '\n' #Переходим на новую строку для следующего кортежа hop_count +=1 bot.send_message(message.from_user.id, text=f'Количество строк - {hop_count}') bot.send_message(message.from_user.id, text=string_to_send) # Отправляю через два разных сообщения, чтобы увидеть кол-во строк до того, как свалится с ошибкой
)
- Нечитаемый формат данных. Пробовал разные варианты (табуляция и тд), но табличные данные, возвращаемые в виде множества строк все равно не особо воспринимаются глазом.
Возможно, решением обеих проблем будет автоматическая генерация статьи Telegraph (не уверен можно ли туда пихать таблицы, пока что не нагуглил, и возможность вообще ее генерировать автоматически тоже пока что вызывает сомнения :D)
Возможно, есть способ преобразовывать это все в эксель файл и отправлять через бота скрины данных в этой эксельке, чего, в принципе, будет минимально достаточно для закрытия потребности
Был бы очень рад услышать ваши варианты доработки того, что у меня сейчас существует, либо ваше видение решения задачи
Заранее извиняюсь за свой код, делаю это на питоне не так часто
Ответы (1 шт):
сплитить по ограничению кол-ва знаков
я просто оставлю это как пример:
if len(data) > 4096:
for x in range(0, len(report), 4096):
bot.send_message(message.chat.id, '{}'.format(report[x:x + 4096]))
else:
bot.send_message(message.chat.id, '{}'.format(report))
Нечитаемый формат данных
я использую для вывода небольших таблиц:
bot.send_message(message.chat.id, '`{}`'.format(data), parse_mode='Markdown')
автоматическая генерация статьи Telegraph
это возможно - https://telegra.ph/api и бот @telegraph
способ преобразовывать это все в эксель файл и отправлять через бота скрины данных в этой эксельке
потребуется
from oauth2client.service_account import ServiceAccountCredentials
import gspread
# Google
gscope = ['https://spreadsheets.google.com/feeds', 'https://www.googleapis.com/auth/drive']
gcredentials = 'ваш файл полученный по инструкции.json'
gdocument = 'название таблицы'
чтобы бот мог записывать в Таблицу:
Настройка интеграции с Google Drive, Google Spreadsheet
1. https://console.developers.google.com/
2. Библиотека – Создать проект
3. Поиск в библиотеке API:
a. Google Drive – Включить
b. Создать учётные данные
c. Какой API вы используете – Google Drive API
d. Откуда вы будете вызывать API – Веб-Сервер
e. К каким данным вы будете обращаться – Данные приложения
f. Используете этот API для App Engine или Compute Engine – Нет
g. Выбрать тип учётных данных
h. Роль – Проект – Редактор
i. Тип ключа – JSON
j. Продолжить (загрузка ключа в формате JSON)
4. Открыть полученный файл JSON
5. Скопировать значение поля "client_email"
6. https://docs.google.com/spreadsheets/
7. Создать новую таблицу
8. Настройки доступа
9. Ввести значение из п.5 и предоставить доступ на редактирование
Запись в Гугл Таблицу: дата, время, id, переменные
# Запись в Google Sheet Bot
def add_to_gsheet(message, data, text):
credentials = ServiceAccountCredentials.from_json_keyfile_name(gcredentials, gscope)
gc = gspread.authorize(credentials)
wks = gc.open(gdocument).sheet1
# noinspection PyBroadException
try:
# убрать если нужно чтобы была реакция при ЛС боту
if message.chat.type == 'private':
return
except Exception:
pass
wks.append_row(
[datetime.now().strftime('%d.%m.%Y %H:%M:%S'), 'Имя бота', message.from_user.id, text, '---', data])
вызываем например так:
add_to_gsheet(message, 'отмена проведения ' + number_check, 'чек')
таким образом в Таблицу будет записано следующее
06.04.2020 18:25:50 Имя бота 123 чек --- отмена проведения ММА00031234
Далее получим данные таблицы как pdf, преобразуем в jpg и отправим:
from pdf2image import convert_from_path
import requests
import os
from sys import platform
import fnmatch
if platform == "linux" or platform == "linux2":
pass
path = 'files/'
elif platform == "win32":
poppler = 'PATH/poppler/bin'
path = 'PATH/files/'
# Google Spreadsheet
# Param export GS
# &format=pdf //export format
# &size=a4 //A3/A4/A5/B4/B5/letter/tabloid/legal/statement/executive/folio
# &portrait=false //true= Potrait / false= Landscape
# &scale=1 //1= Normal 100% / 2= Fit to width / 3= Fit to height / 4= Fit to Page
# &top_margin=0.00 //All four margins must be set!
# &bottom_margin=0.00 //All four margins must be set!
# &left_margin=0.00 //All four margins must be set!
# &right_margin=0.00 //All four margins must be set!
# &gridlines=false //true/false
# &printnotes=false //true/false
# &pageorder=2 //1= Down, then over / 2= Over, then down
# &horizontal_alignment=CENTER //LEFT/CENTER/RIGHT
# &vertical_alignment=TOP //TOP/MIDDLE/BOTTOM
# &printtitle=false //true/false
# &sheetnames=false //true/false
# &fzr=false //true/false
# &fzc=false //true/false
# &attachment=false //true/false
gs_id = '1QJRxp...gVVBIw'
gs_url = 'https://docs.google.com/spreadsheets/d/' + gs_id + '/export?format=pdf&gid='
gs_param = '&size=a5&portrait=false&vertical_alignment=MIDDLE&horizontal_alignment=CENTER'
gs_table = [581871535, 1884134963, 1426883343] # gid
def main(gid):
# Download Google Spreadsheet
response = requests.get(gs_url + str(gid) + gs_param)
with open(path + 'test-table.pdf', 'wb') as out_file:
for chunk in response:
out_file.write(chunk)
# Google Spreadsheet pdf to jpg
convert_from_path(path + 'test-table.pdf', poppler_path=poppler, output_folder=path,
output_file='test-table', fmt='jpg')
# Send Google spreadsheet jpg send from bot
requests.post('https://api.telegram.org/bot' + bot + '/sendPhoto',
files={'photo': open(path + 'test-table0001-1.jpg', 'rb')},
data={'chat_id': 'id_tlgrm'})
for gid in gs_table:
main(gid)
os.remove(fnmatch.filter(os.listdir('files'), '*.pdf'))
os.remove(fnmatch.filter(os.listdir('files'), '*.jpg'))
gs_param подбираются индивидуально
- pip install pdf2image
- pip install requests
- pip install PySocks # to use proxies
- poppler-windows
- Linux - install
poppler-utils