Боти аввалин
Чаро боти асинхронӣ лозим аст
Боти ёдраскунанда ҳамзамон бо одамони гуногун суҳбат мекунад: яке вақт интихоб мекунад, дигаре рӯйхатро мекушояд, сеюмӣ фармон мефиристад. Барнома бештари вақт ҳисоб намекунад, балки шабакаро интизор мешавад. aiogram 3 имкон медиҳад, ки ин вақти интизорӣ барои коркарди паёмҳои дигар истифода шавад. Дар курс пайдарпай фармонҳо, тугмаҳо, муколамаҳо ва ёдрасиҳо пайдо мешаванд.
Аз роҳи як паём оғоз мекунем: Telegram навсозӣ мефиристад, китобхона объектҳои Python месозад, шартҳоро месанҷад ва функсияи мувофиқро даъват мекунад. Ҳамаи мисолҳои зер бе Telegram бо aiogram 3.31.0 кор мекунанд. Ададҳои мисоли масирдиҳӣ коркардкунандаи интихобшударо нишон медиҳанд, на ҷавоби воқеӣ ба корбарро.
1. Корутина ва интизорӣ
Корутина (coroutine) — ҳисобест, ки онро боздошта, баъд идома додан мумкин аст. Даъвати функсияи async def объекти корутина месозад; бадани он ҳангоми интизор шудан бо await ё ҳамчун вазифа ба нақша гирифтан иҷро мешавад. Давраи рӯйдодҳо (event loop) байни вазифаҳои омода мегузарад. asyncio.run(main()) давра сохта, корутинаи асосиро иҷро мекунад.
await маънои «сохтани боз як thread»-ро надорад. Агар амали интизоршаванда бозистад, он ба кори дигар имкони пеш рафтан медиҳад. Дар мисоли омӯзишӣ asyncio.sleep(0) идоракуниро бе таъхири воқеӣ месупорад. gather чанд корутинаро интизор шуда, натиҷаҳоро бо тартиби аргументҳои додашуда бармегардонад.
import asyncio
async def double(value):
await asyncio.sleep(0)
return value * 2
async def main():
a, b = await asyncio.gather(double(3), double(5))
print(a, b)
asyncio.run(main())
Натиҷа:
6 10
Аввал ҳар ду корутина ба нуқтаи интизорӣ мерасанд, баъд ҳисобро идома медиҳанд. Дар бот ба ҷойи интизории омӯзишӣ аксар вақт await message.answer(...) меистад: фиристодан дархости шабакавиро талаб мекунад. Ҳисоби дарози одӣ бе нуқтаҳои интизорӣ боз ҳам давраи рӯйдодҳоро бозмедорад.
2. Паём ва дархости ҷавоб
Message — объекти паёми воридшуда аст. message.text матн ё None, message.from_user фиристанда ва message.chat чати қабулкунандаро дар бар мегирад. Шахс метавонад username ва майдонҳои дигари ихтиёрӣ надошта бошад. Баъзе намудҳои паём from_user ҳам надоранд; агар боти шумо чунин паёмҳоро қабул кунад, мавҷудияти объектро санҷед.
Методи message.answer(...) дархости SendMessage-ро бо рақами ҳамон чат тайёр мекунад. Дар мисоли навбатӣ танҳо дархостро мебинем: бе await ва пайвастшавӣ он чизе намефиристад. Номи Mina маълумоти санҷишӣ ва OK ҷавоби кӯтоҳи шартӣ аст.
from aiogram.types import Chat, Message, User
message = Message(message_id=1, date=0,
chat=Chat(id=42, type="private"),
from_user=User(id=9, is_bot=False, first_name="Mina"),
text="abc")
request = message.answer("OK")
print(message.from_user.first_name, message.from_user.username)
print(type(request).__name__, request.chat_id, request.text)
Натиҷа:
Mina None
SendMessage 42 OK
Дар коркардкунандаи асинхронии воқеӣ await message.answer(...) лозим аст, то aiogram дархостро тавассути боти пайвастшуда фиристад. message.reply(...) ҷавоберо месозад, ки ба паёми аслӣ ишора мекунад. Рақами корбар ва рақами чат вазифаҳои гуногун доранд: дар гурӯҳ чанд кас ба як чат менависанд.
3. Bot, Router ва Dispatcher
Bot токен ва сессияи шабакавиро барои Telegram Bot API нигоҳ медорад. Router коркардкунандагони рӯйдодҳоро ҷамъ мекунад. Коркардкунанда (handler) — функсияест, ки китобхона барои рӯйдоди мувофиқ даъват мекунад. Dispatcher навсозиҳоро қабул карда, ба Router-ҳои пайвастшуда равона мекунад. dp.include_router(router) маҷмӯи коркардкунандагонро мепайвандад.
Декоратори @router.message(...) функсияро ҳангоми иҷрои таърифаш сабт мекунад. Филтр дар қавс муайян мекунад, ки паём мувофиқ аст ё не. Command("weather") фармонро пурра месанҷад, F.text бошад мавҷудияти матни ғайрихолиро. CommandStart() барои /start пешбинӣ шудааст.
import asyncio
from aiogram import Bot, Dispatcher, Router, F
from aiogram.filters import Command
from aiogram.types import Chat, Message, Update
router = Router()
@router.message(Command("weather"))
async def weather(message):
print(1)
@router.message(F.text)
async def text_only(message):
print(2)
async def main():
dp = Dispatcher()
dp.include_router(router)
bot = Bot("1:TEST")
try:
for i, text in enumerate(["/weather", "/weatherx", "abc"], 1):
message = Message(message_id=i, date=0,
chat=Chat(id=42, type="private"), text=text)
await dp.feed_update(bot, Update(update_id=i, message=message))
finally:
await bot.session.close()
asyncio.run(main())
Натиҷа:
1
2
2
/weather ба коркардкунандаи аввал афтод. /weatherx ба ин фармон баробар нест ва ба дуюм расид. Барои abc ҳам дуюм интихоб шуд. Пас аз аввалин коркардкунандаи мувофиқ коркарди одии рӯйдод қатъ мешавад, ҳатто агар функсия чизе барнагардонад. Дар мисол feed_update навсозиҳои сунъиро мустақим медиҳад: токени санҷишӣ барои муроҷиат ба Telegram истифода намешавад.
Барои оғози воқеӣ бо фармони /newbot аз @BotFather токен гиред, онро дар тағйирёбандаи муҳити BOT_TOKEN нигоҳ доред ва бо os.getenv("BOT_TOKEN") хонед. Дар корутинаи асосӣ await dp.start_polling(bot) навсозиҳоро аз Telegram мегирад. Токен дастрасӣ ба бот медиҳад: онро дар коди нашршуда нагузоред.
4. Филтри F-ро чӣ гуна мехонем
F санҷиши майдонро тасвир мекунад, на худи паёмро. Занҷираи F.text.startswith("#") маънои «матнро гирифта, аввали онро санҷ»-ро дорад. Ҳангоми коркард aiogram онро ба объекти воридшуда татбиқ мекунад. Барои омӯзиш .resolve(message)-ро дастӣ даъват кардан мумкин аст. Табдил ба bool натиҷаи санҷишро равшан нишон медиҳад.
from aiogram import F
from aiogram.types import Chat, Message
for text in ["#python", "python", None]:
message = Message(message_id=1, date=0,
chat=Chat(id=42, type="private"), text=text)
print(bool(F.text.resolve(message)),
bool(F.text.startswith("#").resolve(message)))
Натиҷа:
True True
True False
False False
Матни аввал ҳаст ва бо # оғоз мешавад; матни дуюм ҳаст, вале дигар хел оғоз мешавад; паёми сеюм матн надорад. Ба ҳамин монанд, F.photo аксро месанҷад, F.text.lower() матнро пеш аз муқоисаи минбаъда ба ҳарфҳои хурд мегардонад ва .regexp(...) regular expression-ро татбиқ мекунад. Коркардкунандаи матн шарт нест аксҳоро ҳам қабул кунад.
Дар дохил чӣ мегузарад
Мизи хизматрасониро бо чанд равзана тасаввур кунед. Dispatcher муроҷиатро гирифта, қоидаҳои сабтшудаи Router-ро месанҷад. Аввал шартҳои махсус, баъд шартҳои умумитар санҷида мешаванд. Коркардкунандаи мувофиқ Message мегирад; await дар амали шабакавӣ ба давраи рӯйдодҳо имкон медиҳад, ки муроҷиати дигарро коркард кунад. Пас аз гирифтани натиҷа коркардкунанда идома меёбад. Ин кори ҳамзамон ҳангоми интизорӣ аст, на тезшавии худкори ҳар коди Python.
Хатоҳои маъмул ва ислоҳ
- Фаромӯш кардани интизорӣ.
message.answer("OK")танҳо дархост месозад ва дар Telegram ҷавоб намеояд. Дар коркардкунандаawait message.answer("OK")нависед. - Ҳамаро хеле барвақт гирифтан.
@router.message()пеш аз коркардкунандаи фармони мушаххас он фармонро ҳам мегирад. Коркардкунандаи умумиро ба охир гузаронед; тартиби сабти дастииrouter.message.register(...)-ро низ санҷед. - Ҳатмӣ ҳисобидани матн.
message.text.lower()барои паёми бематнAttributeErrorмедиҳад.F.textистифода кунед ё аввал майдонро санҷед. - Бастани давра.
time.sleep(2)дар дохилиasync defиҷрои вазифаҳои дигарро дар ҳамин thread бозмедорад. Барои интизорӣawait asyncio.sleep(2)истифода кунед; ҳисобҳои вазнин муносибати алоҳида мехоҳанд. - Напайвастани Router. Танҳо эълони Router онро ба Dispatcher илова намекунад. Пеш аз гирифтани навсозиҳо
dp.include_router(router)-ро даъват кунед.
Ёддошт
| Унсур | Вазифа |
|---|---|
async def, await |
Корутина ва интизорӣ бе бастани давра |
Bot |
Токен ва дархостҳо ба Telegram |
Router |
Сабти коркардкунандагон ва филтрҳо |
Dispatcher, include_router |
Қабули навсозиҳо ва пайвасти масирҳо |
Command, CommandStart, F |
Шартҳои интихоби коркардкунанда |
message.answer, message.reply |
Фиристодан ба ҳамон чат; reply ба паём ишора мекунад |
feed_update / start_polling |
Додани навсозии санҷишӣ / гирифтани навсозиҳо аз Telegram |
Дар масъалаҳо санҷиш худаш паём месозад, онҳоро ба бот медиҳад ва ҷавобҳои фиристодаро чоп мекунад. Барои он токени воқеӣ ва шабака лозим нестанд.