Краткий обзор 📖
Telegram имеет огромный интерфейс API, и разработка ботов в настоящее время растет очень быстро и пользуется большим спросом. Для новичков это хорошая возможность получить первую работу и хороший заработок. Возникает вопрос: как начать писать бота?
✔В этом посте вы найдете информацию о том:
- какой язык выбрать;
- какие фреймворки использовать;
- как улучшить разработку бота;
- что делать дальше.
Как выбрать язык? 🤔
Честно говоря, пишите на том языке, который вам ближе всего. Золотого стандарта не существует. Давайте разберемся, почему. Как вы знаете, чтобы получить данные из API, вам нужно написать скрипт, который делает HTTP-запросы. Например, получение данных из API GitHubбудет выглядеть следующим образом:
- на Python (с пакетом requests)
>>> response = requests.get('https://api.github.com')
>>> response.content
b'{"current_user_url":"https://api.github.com/user","current_user_authorizations_html_url":"https://github.com/settings/connections/applications{/client_id}","authorizations_url":"https://api.github.com/authorizations","code_search_url":"https://api.github.com/search/code?q={query}{&page,per_page,sort,order}","commit_search_url":"https://api.github.com/search/commits?q={query}{&page,per_page,sort,order}","emails_url":"https://api.github.com/user/emails","emojis_url":"https://api.github.com/emojis","events_url":"https://api.github.com/events","feeds_url":"https://api.github.com/feeds","followers_url":"https://api.github.com/user/followers","following_url":"https://api.github.com/user/following{/target}","gists_url":"https://api.github.com/gists{/gist_id}","hub_url":"https://api.github.com/hub","issue_search_url":"https://api.github.com/search/issues?q={query}{&page,per_page,sort,order}","issues_url":"https://api.github.com/issues","keys_url":"https://api.github.com/user/keys","notifications_url":"https://api.github.com/notifications","organization_repositories_url":"https://api.github.com/orgs/{org}/repos{?type,page,per_page,sort}","organization_url":"https://api.github.com/orgs/{org}","public_gists_url":"https://api.github.com/gists/public","rate_limit_url":"https://api.github.com/rate_limit","repository_url":"https://api.github.com/repos/{owner}/{repo}","repository_search_url":"https://api.github.com/search/repositories?q={query}{&page,per_page,sort,order}","current_user_repositories_url":"https://api.github.com/user/repos{?type,page,per_page,sort}","starred_url":"https://api.github.com/user/starred{/owner}{/repo}","starred_gists_url":"https://api.github.com/gists/starred","team_url":"https://api.github.com/teams","user_url":"https://api.github.com/users/{user}","user_organizations_url":"https://api.github.com/user/orgs","user_repositories_url":"https://api.github.com/users/{user}/repos{?type,page,per_page,sort}","user_search_url":"https://api.github.com/search/users?q={query}{&page,per_page,sort,order}"}'
- на JavaScript (с помощью метода fetch)
fetch('https://api.github.com')
.then(response => response.json())
.then(data => {
console.log(data)
})
.catch(error => console.error(error))
// data from the response is:
{
current_user_url: 'https://api.github.com/user',
current_user_authorizations_html_url: 'https://github.com/settings/connections/applications{/client_id}',
authorizations_url: 'https://api.github.com/authorizations',
code_search_url: 'https://api.github.com/search/code?q={query}{&page,per_page,sort,order}',
commit_search_url: 'https://api.github.com/search/commits?q={query}{&page,per_page,sort,order}',
emails_url: 'https://api.github.com/user/emails',
emojis_url: 'https://api.github.com/emojis',
events_url: 'https://api.github.com/events',
feeds_url: 'https://api.github.com/feeds',
followers_url: 'https://api.github.com/user/followers',
following_url: 'https://api.github.com/user/following{/target}',
gists_url: 'https://api.github.com/gists{/gist_id}',
hub_url: 'https://api.github.com/hub',
issue_search_url: 'https://api.github.com/search/issues?q={query}{&page,per_page,sort,order}',
issues_url: 'https://api.github.com/issues',
keys_url: 'https://api.github.com/user/keys',
label_search_url: 'https://api.github.com/search/labels?q={query}&repository_id={repository_id}{&page,per_page}',
notifications_url: 'https://api.github.com/notifications',
organization_url: 'https://api.github.com/orgs/{org}',
organization_repositories_url: 'https://api.github.com/orgs/{org}/repos{?type,page,per_page,sort}',
organization_teams_url: 'https://api.github.com/orgs/{org}/teams',
public_gists_url: 'https://api.github.com/gists/public',
rate_limit_url: 'https://api.github.com/rate_limit',
repository_url: 'https://api.github.com/repos/{owner}/{repo}',
repository_search_url: 'https://api.github.com/search/repositories?q={query}{&page,per_page,sort,order}',
current_user_repositories_url: 'https://api.github.com/user/repos{?type,page,per_page,sort}',
starred_url: 'https://api.github.com/user/starred{/owner}{/repo}',
starred_gists_url: 'https://api.github.com/gists/starred',
topic_search_url: 'https://api.github.com/search/topics?q={query}{&page,per_page}',
user_url: 'https://api.github.com/users/{user}',
user_organizations_url: 'https://api.github.com/user/orgs',
user_repositories_url: 'https://api.github.com/users/{user}/repos{?type,page,per_page,sort}',
user_search_url: 'https://api.github.com/search/users?q={query}{&page,per_page,sort,order}'
}
- в GoLang (с пакетом http)
package main
import (
"net/http"
"io/ioutil"
"log"
)
func main() {
res, err := http.Get("https://api.github.com")
if err != nil {
log.Fatal(err)
}
// read body
body, err := ioutil.ReadAll(res.Body)
res.Body.Close()
if err != nil {
log.Fatal(err)
}
if res.StatusCode != 200 {
log.Fatal("Unexpected status code", res.StatusCode)
}
log.Printf("Body: %sn", body)
}
// body from the response is:
Body: {"current_user_url":"https://api.github.com/user","current_user_authorizations_html_url":"https://github.com/settings/connections/applications{/client_id}","authorizations_url":"https://api.github.com/authorizations","code_search_url":"https://api.github.com/search/code?q={query}{&page,per_page,sort,order}","commit_search_url":"https://api.github.com/search/commits?q={query}{&page,per_page,sort,order}","emails_url":"https://api.github.com/user/emails","emojis_url":"https://api.github.com/emojis","events_url":"https://api.github.com/events","feeds_url":"https://api.github.com/feeds","followers_url":"https://api.github.com/user/followers","following_url":"https://api.github.com/user/following{/target}","gists_url":"https://api.github.com/gists{/gist_id}","hub_url":"https://api.github.com/hub","issue_search_url":"https://api.github.com/search/issues?q={query}{&page,per_page,sort,order}","issues_url":"https://api.github.com/issues","keys_url":"https://api.github.com/user/keys","label_search_url":"https://api.github.com/search/labels?q={query}&repository_id={repository_id}{&page,per_page}","notifications_url":"https://api.github.com/notifications","organization_url":"https://api.github.com/orgs/{org}","organization_repositories_url":"https://api.github.com/orgs/{org}/repos{?type,page,per_page,sort}","organization_teams_url":"https://api.github.com/orgs/{org}/teams","public_gists_url":"https://api.github.com/gists/public","rate_limit_url":"https://api.github.com/rate_limit","repository_url":"https://api.github.com/repos/{owner}/{repo}","repository_search_url":"https://api.github.com/search/repositories?q={query}{&page,per_page,sort,order}","current_user_repositories_url":"https://api.github.com/user/repos{?type,page,per_page,sort}","starred_url":"https://api.github.com/user/starred{/owner}{/repo}","starred_gists_url":"https://api.github.com/gists/starred","topic_search_url":"https://api.github.com/search/topics?q={query}{&page,per_page}","user_url":"https://api.github.com/users/{user}","user_organizations_url":"https://api.github.com/user/orgs","user_repositories_url":"https://api.github.com/users/{user}/repos{?type,page,per_page,sort}","user_search_url":"https://api.github.com/search/users?q={query}{&page,per_page,sort,order}"}
Как видно из результатов выполнения кода, разницы нет. Поэтому просто выбирайте язык, на котором вы пишете 😊.
Как выбрать фреймворк? 🏎️
Конечно, хорошо писать API-запросы самостоятельно. Это уменьшает зависимость от сторонних библиотек и позволяет больше контролировать поведение кода. Но когда таких методов больше двадцати, это уже увеличивает размер кода. Становится трудно управлять всей логикой. Именно здесь на помощь приходят сторонние библиотеки (фреймворки). После выбора языка вы можете рассмотреть варианты различных библиотек из списка здесь, на официальной странице Telegram. Для JavaScript я рекомендую использовать node-telegram-bot-api и telegraf. Для Python можно взять pyTelegramBotAPI и aiogram (настоятельно рекомендую).
Давайте начнем кодить первого бота 🐱💻.
Поскольку я в основном пишу код на Python, я предлагаю вам начать разработку ботов с помощью aiogram. Aiogram — это довольно простой и полностью асинхронный фреймворк для Telegram Bot API, написанный на Python 3.7 с использованием asyncio и aiohttp. Он поможет вам сделать ваших ботов быстрее и проще.
-
Установите пакет. Это можно сделать с помощью pip. Также другие способы загрузки библиотеки перечислены здесь.
pip install -U aiogram
-
Давайте создадим структуру проекта. Нам нужны два python-файла:
config.py
иmain.py
. Это будет выглядеть следующим образом: -
Получение токена. Токен — это строка вида
110201543:AAHdqTcvCH1vGWJxfSeofSAs0K5PALDsaw
, которая необходима для авторизации бота и отправки запросов к Bot API. Держите свой токен в безопасности и храните его надежно, он может быть использован кем угодно для управления вашим ботом. Чтобы создать нового, вам нужно «поговорить» с @BotFather и получить токен там. -
Напишите начальный код. Прежде всего, скопируйте токен от БотФатера и вставьте его в
config.py
. Мы используем модульos
для работы с переменными окружения. Это хорошее решение, чтобы сохранить ваш токен в тайне. Пока вы находитесь на стадии разработки, токен может быть виден вам. Но на этапе производства удалите его.import os API_TOKEN = os.getenv('TOKEN', '5135575762:AAF9vytvlcuL-hruAHHMgZ3G2WvLpbZXMSI')
В
main.py
нам нужно импортировать модульlogging
, объектыaiogram
иAPI_TOKEN
изconfig.py
.import logging from aiogram import Bot, Dispatcher, executor from aiogram.types import Message from config import API_TOKEN
Теперь давайте инициализируем объекты бота и диспетчера:
# Configure logging logging.basicConfig(level=logging.INFO) # Initialize bot and dispatcher bot = Bot(token=API_TOKEN) dp = Dispatcher(bot)
Следующий шаг: взаимодействие с ботами начинается с одной команды. Мы можем обрабатывать команды от пользователей следующим образом:
@dp.message_handler(commands=['start', 'help']) async def handle_start(message: Message) -> Message: return await message.reply("Hi!nI'm TestBot!")
Также добавим еще один обработчик для перехвата всех текстовых сообщений:
@dp.message_handler() async def echo(message: Message) -> Message: return await message.answer(message.text)
Последний шаг: запуск длинного опроса. Эта команда запустит нашего бота для перехвата всех обновлений от Telegram API каждую секунду:
if __name__ == '__main__': executor.start_polling(dp, skip_updates=True)
-
В итоге у нас есть два файла:
import os
API_TOKEN = os.getenv('TOKEN', '5135575762:AAF9vytvlcuL-hruAHHMgZ3G2WvLpbZXMSI')
import logging
from aiogram import Bot, Dispatcher, executor
from aiogram.types import Message
from config import API_TOKEN
# Configure logging
logging.basicConfig(level=logging.INFO)
# Initialize bot and dispatcher
bot = Bot(token=API_TOKEN)
dp = Dispatcher(bot)
@dp.message_handler(commands=['start', 'help'])
async def handle_start(message: Message) -> Message:
return await message.reply("Hi!nI'm TestBot!")
@dp.message_handler()
async def echo(message: Message) -> Message:
return await message.answer(message.text)
if __name__ == '__main__':
executor.start_polling(dp, skip_updates=True)
Что мы получили в итоге? 🤩
Запустим нашего бота с помощью команды в терминале:
python main.py
В консоли вы увидите что-то вроде этого:
INFO:aiogram:Bot: testbot [@testmezgoodlebot]
WARNING:aiogram:Updates were skipped successfully.
INFO:aiogram.dispatcher.dispatcher:Start polling.
Теперь давайте перейдем в Telegram и начнем общаться с ботом.
Чтобы начать чат с ботом, перейдите по ссылке, предоставленной BotFather.
Надеюсь, у вас будет такой же результат, как у меня 😺.
Поздравляю! Вы написали своего первого бота! ✨
Да, сейчас это простой эхо-бот, но в следующих постах мы рассмотрим все аспекты разработки ботов. Тогда вы уже сможете создавать ботов любой сложности. Так что ждите моих следующих новых постов.
Ссылки:
- Код бота на GitHub
Спасибо за прочтение! ❤️ ❤️ ❤️