Как отправить таблицы с помощью Telegram Bot API?
Мне нужно отправить данные фондового рынка, и форматирование - отстой. Нужно отправить что-то подобное
| Symbol | Price | Change |
|--------|-------|--------|
| ABC | 20.85 | 1.626 |
| DEF | 78.95 | 0.099 |
| GHI | 23.45 | 0.192 |
| JKL | 98.85 | 0.292 |
Это то, что я пытался.
| Символ | Цена | Изменить |
| -------- | ------- | -------- |
| ABC | 20,85 | 1.626 |
| DEF | 78,95 | 0.099 |
| GHI | 23,45 | 0,192 |
JKL | 98,85 | 0,292 |
10 ответов
Установите для параметра Telegram parse_mode значение HTML
и оберните текст в<pre></pre>
<pre>
| Tables | Are | Cool |
|----------|:-------------:|------:|
| col 1 is | left-aligned | $1600 |
| col 2 is | centered | $12 |
| col 3 is | right-aligned | $1 |
</pre>
Результат в мессенджере Telegram:
Обновлено. Будет проблема с маленькими экранами смартфонов. Так что это плохой метод. Единственный вариант - преобразовать таблицы на картинке и так отправить.:(
Попробуй это
```| Symbol | Price | Change |
|--------|-------|--------|
| ABC | 20.85 | 1.626 |
| DEF | 78.95 | 0.099 |
| GHI | 23.45 | 0.192 |
| JKL | 98.85 | 0.292 |```
Импортируйте библиотеку "prettytable" в Python для форматирования таблицы:
import prettytable as pt
from telegram import ParseMode
from telegram.ext import CallbackContext, Updater
def send_table(update: Updater, context: CallbackContext):
table = pt.PrettyTable(['Symbol', 'Price', 'Change'])
table.align['Symbol'] = 'l'
table.align['Price'] = 'r'
table.align['Change'] = 'r'
data = [
('ABC', 20.85, 1.626),
('DEF', 78.95, 0.099),
('GHI', 23.45, 0.192),
('JKL', 98.85, 0.292),
]
for symbol, price, change in data:
table.add_row([symbol, f'{price:.2f}', f'{change:.3f}'])
update.message.reply_text(f'<pre>{table}</pre>', parse_mode=ParseMode.HTML)
# or use markdown
update.message.reply_text(f'```{table}```', parse_mode=ParseMode.MARKDOWN_V2)
Вы получите сообщение вроде:
+--------+-------+--------+
| Symbol | Price | Change |
+--------+-------+--------+
| ABC | 20.85 | 1.626 |
| DEF | 78.95 | 0.099 |
| GHI | 23.45 | 0.192 |
| JKL | 98.85 | 0.292 |
+--------+-------+--------+
Вы можете использовать разметку HTML или Markdown, чтобы отправить что-то вроде <pre>
в HTML. Так же, как этот пример.
Самый простой и профессиональный метод – использоватьTelegram Web App Bot
, который был добавлен в недавнем обновлении.
шаг 1: создайте html-файл и напишите свою таблицу.
Шаг 2 : добавьте этот скрипт в свой html-файл.<script src="https://telegram.org/js/telegram-web-app.js"></script>
шаг 3 : перенаправить пользователя на страницу с помощью этого метода API
{
"text": "Test web_app",
"web_app": {
"url": "https://yourDomain/yourFile.html"
}
}
примечание: страница будет отображаться на странице бота, а не в браузере
для получения дополнительной информации прочитайте официальный документ: https://core.telegram.org/bots/webapps#initializing-web-apps
Вот мое решение, использующее puppeteer для снимка экрана элемента таблицы.
Прежде всего, вам нужно сгенерировать HTML-код таблицы, вот код для генерации этого кода.
async function generateHtml(rows) {
return `<!DOCTYPE html>
<html>
<head>
<style>
thead,
tfoot {
background-color: #3f87a6;
color: #fff;
}
tbody {
background-color: #e4f0f5;
}
caption {
padding: 10px;
caption-side: bottom;
}
table {
border-collapse: collapse;
border: 2px solid rgb(200, 200, 200);
letter-spacing: 1px;
font-family: sans-serif;
font-size: .8rem;
}
td,
th {
border: 1px solid rgb(190, 190, 190);
padding: 5px 10px;
}
td {
text-align: center;
}
</style>
</head>
<body>
<table>
<caption>Pornhub Pages Summary</caption>
<thead>
<tr>
<th>ID</th>
<th scope="col">Progress</th>
<th scope="col">Stucked</th>
<th scope="col">Finished</th>
<th scope="col">Busy</th>
</tr>
</thead>
<tbody>
${rows}
</tbody>
</table>
</body>
</html>`
}
И вот код для генерацииrows
аргумент вышеуказанной функции
async function getTheImgOfTheSummaryOfThePages() {
const rows = []
for (const [index, val] of statuesOfThePages.entries()) {
const row = `<tr>
<th scope="row">${index}</th>
<th>${val.progress}</th>
<th>${val.stucked}</th>
<th>${val.finished}</th>
<th>${val.pageBusy}</th>
</tr>`
rows.push(row)
}
const path = './summaryOfThePagesOfPornhub.png'
const html = await generateHtml(rows.join('\n'))
await util.takescrrenshotOnTheHtml(html, browser, path, 'table')
return path
}
А вот код скриншота элемента table
async function takescrrenshotOnTheHtml(html, browser, pathToSave, onElement) {
const page = await newPage(browser);
await page.setContent(html)
const element = await page.$(onElement)
await element.screenshot({path: pathToSave})
await page.close()
}
Ну, вам просто нужно изменить заголовки таблицы и строки таблицы
Я нашел эту библиотеку - TableJs - которая решает эту проблему. Отлично работает в клиентах для настольных ПК, однако клиенты Android не отображали его должным образом.
import warnings
from PIL import Image, ImageDraw, ImageFont
def table_to_image(my_table):
warnings.filterwarnings('ignore', category=DeprecationWarning)
font = ImageFont.truetype("courbd.ttf", 15)
text_width, text_height = font.getsize_multiline(my_table.get_string())
im = Image.new("RGB", (text_width + 15, text_height + 15), "white")
draw = ImageDraw.Draw(im)
draw.text((7, 7), my_table.get_string(), font=font, fill="black")
im.show()
im.save(my_table_image.png, 'PNG')
Я написал код для создания html-таблицы Telegram из массива строк.
Просто создайте массив со строками с данными столбцов, разделенными ";" и этот код выведет готовую таблицу Telegram.
Наслаждайтесь, разберитесь с параметрами :)
Вы должны использовать «parse_mode» = «html» при отправке сообщения в Telegram Api.
public string BuildTelegramTable(
List<string> table_lines,
string tableColumnSeparator = "|", char inputArraySeparator = ';',
int maxColumnWidth = 0, bool fixedColumnWidth = false, bool autoColumnWidth = false,
int minimumColumnWidth = 4, int columnPadRight = 0, int columnPadLeft = 0,
bool beginEndBorders = true)
{
var prereadyTable = new List<string>() { "<pre>" };
var columnsWidth = new List<int>();
var firstLine = table_lines[0];
var lineVector = firstLine.Split(inputArraySeparator);
if (fixedColumnWidth && maxColumnWidth == 0) throw new ArgumentException("For fixedColumnWidth usage must set maxColumnWidth > 0");
else if (fixedColumnWidth && maxColumnWidth > 0)
{
for(var x=0;x<lineVector.Length;x++)
columnsWidth.Add(maxColumnWidth + columnPadRight + columnPadLeft);
}
else
{
for(var x=0;x<lineVector.Length;x++)
{
var columnData = lineVector[x].Trim();
var columnFullLength = columnData.Length;
if (autoColumnWidth)
table_lines.ForEach(line => columnFullLength = line.Split(inputArraySeparator)[x].Length > columnFullLength ? line.Split(inputArraySeparator)[x].Length : columnFullLength);
columnFullLength = columnFullLength < minimumColumnWidth ? minimumColumnWidth : columnFullLength;
var columnWidth = columnFullLength + columnPadRight + columnPadLeft;
if (maxColumnWidth > 0 && columnWidth > maxColumnWidth)
columnWidth = maxColumnWidth;
columnsWidth.Add(columnWidth);
}
}
foreach(var line in table_lines)
{
lineVector = line.Split(inputArraySeparator);
var fullLine = new string[lineVector.Length+(beginEndBorders ? 2 : 0)];
if (beginEndBorders) fullLine[0] = "";
for(var x=0;x<lineVector.Length;x++)
{
var clearedData = lineVector[x].Trim();
var dataLength = clearedData.Length;
var columnWidth = columnsWidth[x];
var columnSizeWithoutTrimSize = columnWidth - columnPadRight - columnPadLeft;
var dataCharsToRead = columnSizeWithoutTrimSize > dataLength ? dataLength : columnSizeWithoutTrimSize;
var columnData = clearedData.Substring(0,dataCharsToRead);
columnData = columnData.PadRight(columnData.Length + columnPadRight);
columnData = columnData.PadLeft(columnData.Length + columnPadLeft);
var column = columnData.PadRight(columnWidth);
fullLine[x+(beginEndBorders ? 1 : 0)] = column;
}
if (beginEndBorders) fullLine[fullLine.Length - 1] = "";
prereadyTable.Add(string.Join(tableColumnSeparator,fullLine));
}
prereadyTable.Add("</pre>");
return string.Join("\r\n",prereadyTable);
}