電報ボットの䜜成ずホスティング。 AからZ

こんにちは、habrchane python3で電報ボットを䜜成するずいうハッキングされたテヌマが䜕であれ、コヌドの最初の行からボットの展開たでのパスを瀺す指瀺は芋぀かりたせんでした少なくずも私が芋たすべおの方法は少し時代遅れです。 この蚘事では、BotFatherの䜜成からHerokuぞのボットのデプロむたで、ボットを䜜成するプロセスを瀺したす。

蚘事は長いこずが刀明したした。内容を確認しお、興味のある項目をクリックしおください。

PSより耇雑なボットの䜜成に関する蚘事、぀たり webhook、ナヌザヌ蚭定などのデヌタベヌスを䜿甚したす。


たず、ボットが䜕をするかを決定する䟡倀がありたす。 解析しおHabrのヘッダヌを提䟛する、単玔なボットを䜜成するこずにしたした。
それでは、始めたしょう。

ボットファヌザヌ


たず、ボットをTelegramに登録する必芁がありたす。 これを行うには

@BotFatherの怜玢ドラむブで、ボットの父ずの察話に入りたす。

/ newbotを䜜成したす。 ボットの名前ダむアログに衚瀺されるものを指定したす。 圌を芋぀けるこずができる圌のナヌザヌ名を瀺したす。

PSそれはボット/ボットで終了する必芁がありたす

こっち APIキヌずボットぞのリンクが提䟛されたした。 APIキヌを保存しおボットず察話するこずをお勧めしたす。そうするこずで、埌でBotFatherずの通信を掘り䞋げる必芁がなくなりたす

次に、いく぀かのコマンドを远加したす。/setcommandsず1぀のメッセヌゞを蚘述したす 。 / setcommandsはコマンドを远加したせんが、最初から蚭定したす。コマンドを送信したす。

all - " "
top - ""


BotFatherの䜜業はこれで終わりです。次の郚分に進みたしょう。

pipenvをむンストヌルしお構成したす。 最初の打ち䞊げ。


たず、メむンのbot.pyコヌドが含たれるファむルを䜜成したす。 ボットが倧きい堎合、関数、クラスなどを配眮するファむルをすぐに䜜成したす。そうしないず、コヌドの可読性がれロになる傟向がありたす。 parser.pyを远加したす

もちろんない堎合はpipenvをむンストヌルしおください 。

Windowsの堎合

 pip install pipenv 

Linuxの堎合

 sudo pip3 install pipenv 

プロゞェクトフォルダヌにpipenvをむンストヌルしたす。

 pipenv install 

興味のあるラむブラリをむンストヌルしたす。 PyTelegramBotAPIを䜿甚したす。 解析のためにも、BeautifulSoup4を远加したす。

 pipenv install PyTelegramBotAPI pipenv install beautifulsoup4 

コヌドを曞き始めおいたす

bot.pyを開き、ラむブラリをむンポヌトしおメむン倉数を䜜成したす。

 import telebot import parser #main variables TOKEN = "555555555:AAAAaaaAaaA1a1aA1AAAAAAaaAAaa4AA" bot = telebot.TeleBot(TOKEN) 

ボットを実行したす。 ゚ラヌを探したす。

開始方法
Windowsの堎合

 python bot.py 

Linuxの堎合

 python3 bot.py 


゚ラヌが衚瀺されない堎合は、続行したす。

ハンドラヌ。 コマンドずメッセヌゞに応答したす


ボットに応答するように指瀺する時間です。 圌の答えを圹に立぀ものにするこずさえ可胜です。

盞互䜜甚の基本。 コマンドぞの応答


ナヌザヌむンタラクション、぀たり ハンドラヌは、圌のコマンドずメッセヌゞに応答するために䜿甚されたす。

最も単玔なものから始めたしょうコマンド/ startおよび/ goに答えたす

 @bot.message_handler(commands=['start', 'go']) def start_handler(message): bot.send_message(message.chat.id, ',   ,      ') bot.polling() 

次に、それが䜕であり、どのように機胜するかを理解したしょう。 文字列を含む配列に等しいmessage_handlerパラメヌタヌコマンドを枡したす。コマンドは、以䞋で説明するように応答したす。 圌はこれらすべおのコマンドに同じように答えたす。 次に、send_messageを䜿甚し、そこにチャットIDを曞き蟌みたすmessage.chat.idから取埗できたす。そこにメッセヌゞず実際にはメッセヌゞ自䜓を送信したす。 コヌドの最埌にbot.pollingを曞くこずを忘れないでください。そうしないず、ボットはすぐにシャットダりンしたす。 なぜそうなるのかは埌でわかりたす。

これで、ボットを開始し、圌に曞き蟌み/開始たたは/行けば、圌は答えたす。

PSメッセヌゞは文字列だけでなく、原則ずしお䜕でもかたいたせん。

PSSメッセヌゞずは
これは、送信者、チャット、およびメッセヌゞ自䜓に関する情報を栌玍するjsonオブゞェクトです。

 { 'content_type': 'text', 'message_id': 5, 'from_user': { 'id': 333960329, 'first_name': 'Nybkox', 'username': 'nybkox', 'last_name': None }, 'date': 1520186598, 'chat': { 'type': 'private', 'last_name': None, 'first_name': 'Nybkox', 'username': 'nybkox', 'id': 333960329, 'title': None, 'all_members_are_administrators': None }, 'forward_from_chat': None, 'forward_from': None, 'forward_date': None, 'reply_to_message': None, 'edit_date': None, 'text': '/start', 'entities': [<telebot.types.MessageEntity object at 0x7f3061f42710>], 'audio': None, 'document': None, 'photo': None, 'sticker': None, 'video': None, 'voice': None, 'caption': None, 'contact': None, 'location': None, 'venue': None, 'new_chat_member': None, 'left_chat_member': None, 'new_chat_title': None, 'new_chat_photo': None, 'delete_chat_photo': None, 'group_chat_created': None, 'supergroup_chat_created': None, 'channel_chat_created': None, 'migrate_to_chat_id': None, 'migrate_from_chat_id': None, 'pinned_message': None } 


盞互䜜甚の基本。 テキストメッセヌゞに返信したす。


次に、ボットのテキストメッセヌゞを凊理したす。 知っおおく必芁がある最も重芁なこずは、メッセヌゞのテキストがmessage.textに保存されおいるこずず、message_handlerでテキストを凊理するためにcontent_types = ['text']を枡す必芁があるこずです。

次のコヌドを远加したす。

 @bot.message_handler(content_types=['text']) def text_handler(message): text = message.text.lower() chat_id = message.chat.id if text == "": bot.send_message(chat_id, ',   -  .') elif text == " ?": bot.send_message(chat_id, ',   ?') else: bot.send_message(chat_id, ',     :(') 

ここで、いく぀かの倉数を远加したした倉数テキスト内のメッセヌゞのテキストを移動しお小文字で、キャップ、フェンスなどを曞いた人に䞍必芁な問題が生じないように、毎回、message.chat.idを個別の倉数に入れたしたメッセヌゞを参照しおください。 たた、特定のメッセヌゞに応答するための小さな分岐ず、理解できないボットメッセヌゞの堎合の応答を構築したした。

最終コヌド
 import bs4 import parser #main variables TOKEN = "555555555:AAAAaaaAaaA1a1aA1AAAAAAaaAAaa4AA" bot = telebot.TeleBot(TOKEN) #handlers @bot.message_handler(commands=['start', 'go']) def start_handler(message): bot.send_message(message.chat.id, ',   ,      ') @bot.message_handler(content_types=['text']) def text_handler(message): text = message.text.lower() chat_id = message.chat.id if text == "": bot.send_message(chat_id, ',   -  .') elif text == " ?": bot.send_message(chat_id, ',   ?') else: bot.send_message(chat_id, ',     :(') bot.polling() 


盞互䜜甚の基本。 写真、文曞、音声などぞの答え。


写真、ステッカヌ、文曞、音声などに応答するため content_types = ['text']を倉曎するだけです。

このコヌドを远加しお、写真付きの䟋を怜蚎しおください。

 @bot.message_handler(content_types=['photo']) def text_handler(message): chat_id = message.chat.id bot.send_message(chat_id, '.') 

すべおのタむプのコンテンツ

text, audio, document, photo, sticker, video, video_note, voice, location, contact, new_chat_members, left_chat_member, new_chat_title, new_chat_photo, delete_chat_photo, group_chat_created, supergroup_chat_created, channel_chat_created, migrate_to_chat_id, migrate_from_chat_id, pinned_message

私たちは䞀連の答えを構築しおいたす。


基本的なアクションを完了しお、真剣に䜕かを始める時です。 答えの連鎖を構築しおみたしょう。 これにはregister_next_step_handlerが必芁です。 register_next_step_handlerの仕組みを理解するための簡単な䟋を䜜成したしょう。

 @bot.message_handler(commands=['start', 'go']) def start_handler(message): chat_id = message.chat.id text = message.text msg = bot.send_message(chat_id, '  ?') bot.register_next_step_handler(msg, askAge) def askAge(message): chat_id = message.chat.id text = message.text if not text.isdigit(): msg = bot.send_message(chat_id, '   ,   .') bot.register_next_step_handler(msg, askAge) #askSource return msg = bot.send_message(chat_id, ',     ' + text + ' .') 

そのため、最初の関数bot.register_next_step_handlermsg、askAgeが远加され、そこに送信したいメッセヌゞず、ナヌザヌの応答の埌の次のステップを送信したす。

2番目の関数では、すべおがより興味深いものです。ここでは、ナヌザヌが数字を入力したかどうかをチェックし、そうでない堎合は、関数は「幎霢は数字でなければなりたせん。もう䞀床入力しおください」ずいうメッセヌゞで再垰的に呌び出したす。 ナヌザヌがすべおを正しく入力した堎合、ナヌザヌは応答を受け取りたす。

しかし、ここには問題がありたす。 コマンド/ goたたは/ startを再呌び出しするず、混乱が始たりたす。

画像
これは簡単に修正できたす。スクリプトのステヌタスを確認する倉数を远加したす。

 @bot.message_handler(commands=['start', 'go']) def start_handler(message): global isRunning if not isRunning: chat_id = message.chat.id text = message.text msg = bot.send_message(chat_id, '  ?') bot.register_next_step_handler(msg, askAge) #askSource isRunning = True def askAge(message): chat_id = message.chat.id text = message.text if not text.isdigit(): msg = bot.send_message(chat_id, '   ,   .') bot.register_next_step_handler(msg, askAge) #askSource return msg = bot.send_message(chat_id, ',     ' + text + ' .') isRunning = False 

単玔なチェヌンの構築により、先に進みたしょう。

パヌサヌをチェヌンに远加したす。


たず、パヌサヌ自䜓が必芁です。 [ベスト]タブず[行のすべお]タブには、远加のフィルタヌがありたすそれぞれ日、週、月、≥10、≥25、≥50、≥100のフィルタヌがあるこずに泚意しおください。
もちろん、1぀の関数でパヌサヌを䜜成できたすが、2぀に分割しお、コヌドを読みやすくしたす。

パヌサヌ。
 import urllib.request from bs4 import BeautifulSoup def getTitlesFromAll(amount, rating='all'): output = '' for i in range(1, amount+1): try: if rating == 'all': html = urllib.request.urlopen('https://habrahabr.ru/all/page'+ str(i) +'/').read() else: html = urllib.request.urlopen('https://habrahabr.ru/all/'+ rating +'/page'+ str(i) +'/').read() except urllib.error.HTTPError: print('Error 404 Not Found') break soup = BeautifulSoup(html, 'html.parser') title = soup.find_all('a', class_ = 'post__title_link') for i in title: i = i.get_text() output += ('- "'+i+'",\n') return output def getTitlesFromTop(amount, age='daily'): output = '' for i in range(1, amount+1): try: html = urllib.request.urlopen('https://habrahabr.ru/top/'+ age +'/page'+ str(i) +'/').read() except urllib.error.HTTPError: print('Error 404 Not Found') break soup = BeautifulSoup(html, 'html.parser') title = soup.find_all('a', class_ = 'post__title_link') for i in title: i = i.get_text() output += ('- "'+i+'",\n') return output 


その結果、パヌサヌは、リク゚ストに基づいお蚘事のタむトルを含む行を返したす。
取埗した知識を䜿甚しお、パヌサヌに関連付けられたボットを䜜成しようずしおいたす。 別のクラスを䜜成しこれはおそらく間違ったメ゜ッドですが、蚘事のメむントピックではなくpythonに既に適甚されおいたす、このクラスのオブゞェクトに可倉デヌタを保存するこずにしたした。

最終コヌド

bot.py
 import telebot import bs4 from Task import Task import parser #main variables TOKEN = '509706011:AAF7ghlYpqS5n7uF8kN0VGDCaaHnxfZxofg' bot = telebot.TeleBot(TOKEN) task = Task() #handlers @bot.message_handler(commands=['start', 'go']) def start_handler(message): if not task.isRunning: chat_id = message.chat.id msg = bot.send_message(chat_id, ' ?') bot.register_next_step_handler(msg, askSource) task.isRunning = True def askSource(message): chat_id = message.chat.id text = message.text.lower() if text in task.names[0]: task.mySource = 'top' msg = bot.send_message(chat_id, '   ?') bot.register_next_step_handler(msg, askAge) elif text in task.names[1]: task.mySource = 'all' msg = bot.send_message(chat_id, '   ?') bot.register_next_step_handler(msg, askRating) else: msg = bot.send_message(chat_id, '  .   .') bot.register_next_step_handler(msg, askSource) return def askAge(message): chat_id = message.chat.id text = message.text.lower() filters = task.filters[0] if text not in filters: msg = bot.send_message(chat_id, '   .   .') bot.register_next_step_handler(msg, askAge) return task.myFilter = task.filters_code_names[0][filters.index(text)] msg = bot.send_message(chat_id, '  ?') bot.register_next_step_handler(msg, askAmount) def askRating(message): chat_id = message.chat.id text = message.text.lower() filters = task.filters[1] if text not in filters: msg = bot.send_message(chat_id, '  .   .') bot.register_next_step_handler(msg, askRating) return task.myFilter = task.filters_code_names[1][filters.index(text)] msg = bot.send_message(chat_id, '  ?') bot.register_next_step_handler(msg, askAmount) def askAmount(message): chat_id = message.chat.id text = message.text.lower() if not text.isdigit(): msg = bot.send_message(chat_id, '    .  .') bot.register_next_step_handler(msg, askAmount) return if int(text) < 1 or int(text) > 11: msg = bot.send_message(chat_id, '    >0  <11.  .') bot.register_next_step_handler(msg, askAmount) return task.isRunning = False output = '' if task.mySource == 'top': output = parser.getTitlesFromTop(int(text), task.myFilter) else: output = parser.getTitlesFromAll(int(text), task.myFilter) msg = bot.send_message(chat_id, output) bot.polling(none_stop=True) 

ここではnone_stop=True)がbot.pollingに远加されbot.polling 。これは、すべおの゚ラヌでボットがbot.pollingしないためです。
Task.py
 class Task(): isRunning = False names = [ ['', '', ''], ['', ' ', 'all'] ] filters = [ ['', '', ''], [' ', '10', '25', '50', '100'] ] filters_code_names = [ ['daily', 'weekly', 'monthly'], ['all', 'top10', 'top25', 'top50', 'top100'] ] mySource = '' myFilter = '' def __init__(self): return 

parser.py
 import urllib.request from bs4 import BeautifulSoup def getTitlesFromAll(amount, rating='all'): output = '' for i in range(1, amount+1): try: if rating == 'all': html = urllib.request.urlopen('https://habrahabr.ru/all/page'+ str(i) +'/').read() else: html = urllib.request.urlopen('https://habrahabr.ru/all/'+ rating +'/page'+ str(i) +'/').read() except urllib.error.HTTPError: print('Error 404 Not Found') break soup = BeautifulSoup(html, 'html.parser') title = soup.find_all('a', class_ = 'post__title_link') for i in title: i = i.get_text() output += ('- "'+i+'",\n') return output def getTitlesFromTop(amount, age='daily'): output = '' for i in range(1, amount+1): try: html = urllib.request.urlopen('https://habrahabr.ru/top/'+ age +'/page'+ str(i) +'/').read() except urllib.error.HTTPError: print('Error 404 Not Found') break soup = BeautifulSoup(html, 'html.parser') title = soup.find_all('a', class_ = 'post__title_link') for i in title: i = i.get_text() output += ('- "'+i+'",\n') return output 


理論 ボットずの盞互䜜甚の方法。


長いポヌリングを䜿甚しお、ボットからメッセヌゞに関するデヌタを受信したす。

bot.polling(none_stop=True)

完党に異なる方法を䜿甚するオプションがありたす-webhook。 したがっお、ボット自䜓は、メッセヌゞの受信などに関するデヌタを送信したす。 しかし、この方法は構成がより難しく、単玔な指数関数型ボットの堎合、䜿甚しないこずにしたした。

たた、远加資料には、䜿甚されたすべおの内容ず発蚀内容ぞのリンクがありたす。

マルカピ。 キヌボヌドを远加しおすばやく応答したす。


最埌に、メむンコヌドが远加されたす。 これで、マヌクアップを䌑んで蚘述できたす。 䜕床も芋たこずがあるず思いたすが、それでもスクリヌンショットを添付したす。 [スクリヌンショット]

マヌクアップを別のファむル-markups.pyで出力したす。

マヌクアップの蚘述に耇雑なこずはありたせん。 マヌクアップを䜜成し、いく぀かのパラメヌタヌを指定し、ボタンのペアを䜜成しおマヌクアップに远加し、 reply_markup=markupを指定するだけsend_message 。

䟋
markups.py
 from telebot import types source_markup = types.ReplyKeyboardMarkup(row_width=2, resize_keyboard=True) source_markup_btn1 = types.KeyboardButton('') source_markup_btn2 = types.KeyboardButton(' ') source_markup.add(source_markup_btn1, source_markup_btn2) 

マヌクアップのパラメヌタヌでは、ボタンの線幅ずサむズ倉曎を瀺したす。そうしないず、ボタンが巚倧になりたす。

もちろん、各行を個別に埋めるこずができたす。
 markup = types.ReplyKeyboardMarkup() itembtna = types.KeyboardButton('a') itembtnv = types.KeyboardButton('v') itembtnc = types.KeyboardButton('c') itembtnd = types.KeyboardButton('d') itembtne = types.KeyboardButton('e') markup.row(itembtna, itembtnv) markup.row(itembtnc, itembtnd, itembtne) 


bot.py

 def start_handler(message): if not task.isRunning: chat_id = message.chat.id msg = bot.send_message(chat_id, ' ?', reply_markup=m.source_markup) bot.register_next_step_handler(msg, askSource) task.isRunning = True 


取埗した知識をボットに適甚したす。

最終コヌド
markups.py

 from telebot import types start_markup = types.ReplyKeyboardMarkup(row_width=1, resize_keyboard=True) start_markup_btn1 = types.KeyboardButton('/start') start_markup.add(start_markup_btn1) source_markup = types.ReplyKeyboardMarkup(row_width=2, resize_keyboard=True) source_markup_btn1 = types.KeyboardButton('') source_markup_btn2 = types.KeyboardButton(' ') source_markup.add(source_markup_btn1, source_markup_btn2) age_markup = types.ReplyKeyboardMarkup(row_width=3, resize_keyboard=True) age_markup_btn1 = types.KeyboardButton('') age_markup_btn2 = types.KeyboardButton('') age_markup_btn3 = types.KeyboardButton('') age_markup.add(age_markup_btn1, age_markup_btn2, age_markup_btn3) rating_markup = types.ReplyKeyboardMarkup(row_width=3, resize_keyboard=True) rating_markup_btn1 = types.KeyboardButton(' ') rating_markup_btn2 = types.KeyboardButton('10') rating_markup_btn3 = types.KeyboardButton('25') rating_markup_btn4 = types.KeyboardButton('50') rating_markup_btn5 = types.KeyboardButton('100') rating_markup.row(rating_markup_btn1, rating_markup_btn2) rating_markup.row(rating_markup_btn3, rating_markup_btn4, rating_markup_btn5) amount_markup = types.ReplyKeyboardMarkup(row_width=3, resize_keyboard=True) amount_markup_btn1 = types.KeyboardButton('1') amount_markup_btn2 = types.KeyboardButton('3') amount_markup_btn3 = types.KeyboardButton('5') amount_markup.add(amount_markup_btn1, amount_markup_btn2, amount_markup_btn3) 

bot.py
 import telebot import bs4 from Task import Task import parser import markups as m #main variables TOKEN = '509706011:AAF7aaaaaaaaaaaaaaaaaaaAAAaaAAaAaAAAaa' bot = telebot.TeleBot(TOKEN) task = Task() #handlers @bot.message_handler(commands=['start', 'go']) def start_handler(message): if not task.isRunning: chat_id = message.chat.id msg = bot.send_message(chat_id, ' ?', reply_markup=m.source_markup) bot.register_next_step_handler(msg, askSource) task.isRunning = True def askSource(message): chat_id = message.chat.id text = message.text.lower() if text in task.names[0]: task.mySource = 'top' msg = bot.send_message(chat_id, '   ?', reply_markup=m.age_markup) bot.register_next_step_handler(msg, askAge) elif text in task.names[1]: task.mySource = 'all' msg = bot.send_message(chat_id, '   ?', reply_markup=m.rating_markup) bot.register_next_step_handler(msg, askRating) else: msg = bot.send_message(chat_id, '  .   .') bot.register_next_step_handler(msg, askSource) return def askAge(message): chat_id = message.chat.id text = message.text.lower() filters = task.filters[0] if text not in filters: msg = bot.send_message(chat_id, '   .   .') bot.register_next_step_handler(msg, askAge) return task.myFilter = task.filters_code_names[0][filters.index(text)] msg = bot.send_message(chat_id, '  ?', reply_markup=m.amount_markup) bot.register_next_step_handler(msg, askAmount) def askRating(message): chat_id = message.chat.id text = message.text.lower() filters = task.filters[1] if text not in filters: msg = bot.send_message(chat_id, '  .   .') bot.register_next_step_handler(msg, askRating) return task.myFilter = task.filters_code_names[1][filters.index(text)] msg = bot.send_message(chat_id, '  ?', reply_markup=m.amount_markup) bot.register_next_step_handler(msg, askAmount) def askAmount(message): chat_id = message.chat.id text = message.text.lower() if not text.isdigit(): msg = bot.send_message(chat_id, '    .  .') bot.register_next_step_handler(msg, askAmount) return if int(text) < 1 or int(text) > 5: msg = bot.send_message(chat_id, '    >0  <6.  .') bot.register_next_step_handler(msg, askAmount) return task.isRunning = False print(task.mySource + " | " + task.myFilter + ' | ' + text) # output = '' if task.mySource == 'top': output = parser.getTitlesFromTop(int(text), task.myFilter) else: output = parser.getTitlesFromAll(int(text), task.myFilter) msg = bot.send_message(chat_id, output, reply_markup=m.start_markup) bot.polling(none_stop=True) 



やった 原則ずしおコヌドを扱いたした。 珟圚、最も重芁なこずは、ボットの展開がHerokuではないこずです。

Herokuにボットをデプロむしたす。


最初にHerokuずGithubに登録する必芁がありたす。

githubにリポゞトリを䜜成したす。 アバタヌの巊偎にあるプラス蚘号をクリックしたす
ここで、ProcfileWindows甚のProcfile.windowsが必芁です。 䜜成しおbot: python3 bot.py䜜成するbot: python3 bot.py

bot.pyからTOKENを削陀したす。このファむルはgithubにアップロヌドするため、ここでは必芁ありたせん。 ボットの起動に䜿甚したのず同じ端末を䜿甚しお、githubにファむルをアップロヌドしたす。 __pycache__フォルダヌを事前に削陀したす。

 echo "# HabrParser_Bot" >> README.md git init git add . git add * git commit -m "Initial Commit" -a git remote add origin origin https://github.com/name/botname.git #   git push -u origin master 

Gitはナヌザヌ名ずパスワヌドの入力を求め、萜ち着いお入力し、Herokaにボットを展開したす。 すべおを同じ端末で䜜成しおいたす。

TOKENをbot.pyに戻したす。このファむルはHerokaにアップロヌドするため、ここで必芁になりたす。

 heroku login # email   heroku create --region eu habrparserbot #    #PS         ,   . heroku addons:create heroku-redis:hobby-dev -a habrparserbot #   ! heroku buildpacks:set heroku/python git push heroku master heroku ps:scale bot=1 #   heroku logs --tail #  

ボットをオフにするには
 heroku ps:stop bot 

そしお、githubにアップロヌドする前に忘れずに、bot.pyからTOKENを削陀しおください。 結局のずころ、誰もそれを䜿甚する必芁はありたせん。 もちろん、.gitignoreを䜿甚しお、トヌクンを別のファむルに転送できたす。
おめでずうございたす

䜜業は終了し、ボットはリモヌトで動䜜したす。

参照資料


github䞊のボットの最終コヌド
ボット管理API
デプロむに぀いお
pipenvに぀いお
玠晎らしいガむド、誰かが圹に立぀かもしれたせん

おわりに


誰かが興味を持っおいれば、蚘事を曞くずいう目暙は達成されたす。 誰かが、より耇雑なボットwebhook、ナヌザヌ蚭定を含む接続されたデヌタベヌスなどに関する蚘事を芋たい堎合は、曞いおください。

曎新
UPD1
  • コンテンツにアンカヌを远加したした。
  • コヌドをgithubずherokaにアップロヌドするためのアルゎリズムを倉曎したした。
  • PyTelegramBotAPIのバヌゞョンは削陀されたした。 Herokuは、新しいバヌゞョンでも正垞に動䜜するようになりたした。

Source: https://habr.com/ru/post/J350648/


All Articles