Форум программистов, компьютерный форум, киберфорум
Python: API, боты
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.66/47: Рейтинг темы: голосов - 47, средняя оценка - 4.66
0 / 0 / 0
Регистрация: 11.05.2019
Сообщений: 49
Telegram Bot

Разбираюсь с асинхронностью

12.03.2020, 20:58. Показов 9587. Ответов 5
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Всем здрасте)
Есть ботик для скачивания аудио из Ютуба. Решила избежать создания " очереди " из пользователей. Изучила вопрос и поняла, что нужно двигать в сторону асинхронности и вот, что у меня получилось:
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
from __future__ import unicode_literals
import youtube_dl
import misc
import glob 
import os
import telebot
import json
import requests
import psutil
import logging
import requests
import youtube_dl
import asyncio
from unicodedata import normalize
from telebot import util
from sys import argv
from time import sleep
from time import time
from bs4 import BeautifulSoup
from telegram.ext import Updater, CommandHandler, MessageHandler, Filters
 
 
global last_update_id 
last_update_id = 0
TOKEN = misc.token
bot = telebot.AsyncTeleBot(TOKEN)
 
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
                    level=logging.INFO)
 
URL = 'https://api.telegram.org/bot' + TOKEN + '/'
 
# Download data and config
 
download_options = {
    'format': 'bestaudio/best',
    'outtmpl': '%(title)s.%(ext)s',
    'nocheckcertificate': True,
    'postprocessors': [{
        'key': 'FFmpegExtractAudio',
        'preferredcodec': 'm4a',
        'preferredquality': '192',
    }],
}
 
# Song Directory
if not os.path.exists('Songs'):
    os.mkdir('Songs')
else:
    os.chdir('Songs')
 
def normalize_special_char(txt):
    return normalize('NFKD', txt).encode('ASCII', 'ignore').decode('ASCII')
 
 
def search_youtube(text):
    url = 'https://www.youtube.com'
 
    r = requests.get(url + '/results', params={'search_query': text})
    soup = BeautifulSoup(r.content, 'html.parser')
    for tag in soup.find_all('a', {'rel': 'spf-prefetch'}):
        title, video_url = tag.text, url + tag['href']
        if 'googleads' not in video_url:
            return normalize_special_char(video_url) 
 
async def music():
    global text
    video_url = search_youtube(text)
    global chat_id
    music_dict = await skachat(chat_id, video_url)
    
    shlyah = r'C:\pybot\Songs' + '\\' + str(chat_id)
    files_path = os.path.join(shlyah, '*')
    files = sorted(glob.iglob(files_path), key=os.path.getctime, reverse=True)
    
 
# Отправка пользователю аудио файла
async def send_audio(files, text = 'ПАДАЖи ....'):
    #print("send_audio")
    t0 = time()
    
    global chat_id
    for i in files:
        lf = files[0]
        audio = open(i, 'rb')
        bot.send_audio(chat_id, audio)
 
    print(str(time() - t0) + "is end of send_audio")
    del_dl_file(audio, files)
    
# Метод для скачивания аудио из ютуб
 
async def skachat(chat_id, text):
    #print("skachivau")
 
    t0 = time()
    
    with youtube_dl.YoutubeDL(download_options) as dl:
        if 'playlist' in text:
            bot.send_message(chat_id,'skachivau playlist')
        else:
            bot.send_message(chat_id,'skachivau trek')
        dl.download([text])
        
        bot.send_message(chat_id,"fail skachan")
        shlyah = r'C:\pybot\Songs' + '\\' + str(chat_id)
        files_path = os.path.join(shlyah, '*')
        files = sorted(glob.iglob(files_path), key=os.path.getctime, reverse=True)
        await send_audio(files)
    
    print(str(time() - t0) + 'is end of skachat')
 
def del_dl_file(audio, files):
    #sleep(2)
    for i in files:
        try:
            if os.access(i, os.R_OK and os.X_OK):
                os.remove(i)
        except PermissionError:
            audio.close()
            del_dl_file(audio, files)   
    #ist = i.split('\\')[-2]#take chat_id from name of file
    
#проверка: если в названии папки ist есть чат айди пользователя -> отправить ему трек, если же нет -> ist = chat_id (или bot.send_audio(ist, audio))
 
# Метод для проверки новых апдейтов (нет ли новых запросов)
 
async def get_updates():
    #print("get_updates")
    url = URL + 'getupdates'
    r = requests.get(url)
    return r.json()
 
# Метод получения и разбора сообщений от пользователя
 
async def get_message():
    #while True:
    #print("get_message")
    data = await get_updates()
 
    if data :
        last_object = data['result'][-1]
        current_update_id = last_object['update_id']
        global last_update_id
        if last_update_id != current_update_id: 
            last_update_id = current_update_id
            chat_id = last_object['message']['chat']['id']
            message_text = last_object['message']['text']
            message = {'chat_id': chat_id,
                   'message_text': message_text}
            return message
            await get_updates()
            data = None
        return None
    else :
        sleep(1)
 
# Метод для проверки наличия папки пользователя (если ее нет - создать и выбрать ее для загрузки)
 
async def direct():
    #print("direct")
    t0 = time()
 
    if not os.path.exists(r'C:\\pybot\\Songs' + r'\\' + str(chat_id)):
        os.mkdir(r'C:\\pybot\\Songs' + r'\\' + str(chat_id))
        os.chdir(r'C:\\pybot\\Songs' + r'\\' + str(chat_id))
    else:
        os.chdir(r'C:\\pybot\\Songs' + r'\\' + str(chat_id))
    print(str(time() - t0 ) + "is end of direct")
 
# Метод отправки текстовых сообщений пользователям
 
async def send_message(chat_id, text = 'ПАДАЖи ....'):
    #print("send_message")
    url = URL + 'sendmessage?chat_id={}&text={}'.format(chat_id, text)
    requests.get(url)
 
# Запуск скрипта
 
async def main():
    #print("main")
    while True:
        answer = await get_message()
        tasks = []
        if answer:
            global chat_id
            chat_id = answer['chat_id']
            global text
            text = answer['message_text']
            if 'youtube' in text or 'youtu.be' in text:
                #Create or select directory
                t0 = time()
                await direct()
                loop = asyncio.get_event_loop()
                tasks = [loop.create_task(skachat(chat_id, text)), loop.create_task(main())]
                loop.run_until_complete(asyncio.wait(tasks))
 
            elif text == '/start':
                large_text = open("large_text.txt", "rb").read()
                splitted_text = util.split_string(large_text, 3000)
                for text in splitted_text:
                    bot.send_message(chat_id, text)
            else: 
                await direct()
                await music()           
        else :
            continue
        #print(time() - t0)
        
 
if __name__ == '__main__':
    asyncio.run(main())
Задумка была в том, чтобы при старте загрузки трека одному пользователю бот дальше слушал запросы и при появлении нового качал его параллельно предыдущему. Добавила конструкцию асинкио и вроде все правильно, но ругается на большое количество рекурсий. Может кто работал и может подсказать?
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
12.03.2020, 20:58
Ответы с готовыми решениями:

Неполадки с асинхронностью данных в JS
После загрузки обьектов в лист при завершении функции лист становится пустой и в html странице не появляется никакой информации. Файл...

Проблемы с асинхронностью и mysql
function getBalance(peerId) { let Balance = 0 CONNECT.execute("SELECT * FROM `accounts` WHERE `vk_id` = ?", , (err, results) =>...

Проблема с асинхронностью кода
Здравствуйте, есть проблема и не знаю что не так. Помогите кто знает или видит что что то не правильно. Проблема гдето с ст105 - ст142 ...

5
Заклинатель змей
 Аватар для DobroAlex
705 / 560 / 219
Регистрация: 30.04.2016
Сообщений: 2,605
14.03.2020, 17:59
kira_sisad, отладчиком смотрели откуда лезет ошибка (stack trace)? Можно попробовать все упростить, если использовать concurrent.futures. ThreadPoolExecutor как обработчик тасок
1
0 / 0 / 0
Регистрация: 11.05.2019
Сообщений: 49
14.03.2020, 20:07  [ТС]
Вот ошибка:
RecursionError: maximum recursion depth exceeded while calling a Python object
Появляется она при поступлении следующего запроса от пользователя, + бот перестал отправлять скачанные треки после добавления конструкции
Python
1
2
3
4
await direct()
loop = asyncio.get_event_loop()
tasks = [loop.create_task(skachat(chat_id, text)), loop.create_task(main())]
loop.run_until_complete(asyncio.wait(tasks))
0
Заклинатель змей
 Аватар для DobroAlex
705 / 560 / 219
Регистрация: 30.04.2016
Сообщений: 2,605
16.03.2020, 00:13
kira_sisad, стектрейс неплохо было бы посмотреть у ошибки

Я со своей колокольни считаю, что рекурсия возникает тут
Python
1
loop.create_task(main())
Потому что Вы в main() вызываете ещё один main() и т.д
1
0 / 0 / 0
Регистрация: 11.05.2019
Сообщений: 49
16.03.2020, 00:20  [ТС]
Мне очень по душе сейчас любая колокольня)
Просто вот в чем вопрос: нужно сделать так, чтобы пришел пользователь, дал запрос, а бот дальше продолжает слушать других пользователей и выполнять запрос и я туговато соображаю чтобы и мейн в нем же миллион раз не вызывать и чтобы программа проходила круг от начала до конца.
0
Эксперт Python
5438 / 3859 / 1215
Регистрация: 28.10.2013
Сообщений: 9,552
Записей в блоге: 1
16.03.2020, 15:34
Главную функцию (например, main) вы должны один раз положить в главный цикл asyncio.run(main()).
А все прочие таски добавлять через create_task и далее получать результаты одним из вариантов по выбору:
Python
1
2
3
4
5
6
tasks = [loop.create_task(fetch(session,url,conf)) 
                for url in conf.urls
            ]
            # итерация по заданиям не ожидая завершения всех
            for task in asyncio.as_completed(tasks):
                data = await task
или так
Python
1
2
3
4
5
6
7
8
9
10
11
 coroutines = [fetch(session,url,conf) for url in conf.urls]
            # ожидаем завершения корутин
            # return_exceptions возврат исключений как объектов; 
            # то есть в корутинах они не поднимаются
            completed = await asyncio.gather(
                *coroutines,
                return_exceptions=conf.return_exceptions
            ) 
            
            for data in completed:
                  ....
P.S. Использовать gather или wait не сильно принципиально.

Добавлено через 5 минут
Просто в wait корутины делятся на два списка: completed, pending - и итерировать можно по обоим.

Еще и asyncio.Queue() можно задействовать.
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
16.03.2020, 15:34
Помогаю со студенческими работами здесь

Проблема с асинхронностью useState React
Всем привет. Пишу программу погодную на реакте и столкнулся бедой с хуком useState. а именно то что он асинхронен и дату которую я должен...

Разница между асинхронностью и многопоточностью
Было у меня собеседование сегодня. Рассказываю как я облопошился: Вот как-то так ... Стыдно, но и очень интересно. Начал...

Сложное приложение с асинхронностью. Кто посоветует материал?
Я делаю довольно сложное WinForms приложение. И я чувствую, что у меня совсем не идеально реализована асинхронность и многопоточность в...

Не разбираюсь в ошибке
Вот Java код! public class TemperatureConverter { public char convertTemp(int temperature, char convertTo){ if (convertTo...

Не разбираюсь в интегралах (
Не разбираюсь в интегралах,все задания сделала,а это не могу (((((((((((( И застряла на следующем задании: Дана плотность распределения...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
6
Ответ Создать тему
Новые блоги и статьи
http://iceja.net/ математические сервисы
iceja 20.01.2026
Обновила свой сайт http:/ / iceja. net/ , приделала Fast Fourier Transform экстраполяцию сигналов. Однако предсказывает далеко не каждый сигнал (см ограничения http:/ / iceja. net/ fourier/ docs ). Также. . .
http://iceja.net/ сервер решения полиномов
iceja 18.01.2026
Выкатила http:/ / iceja. net/ сервер решения полиномов (находит действительные корни полиномов методом Штурма). На сайте документация по API, но скажу прямо VPS слабенький и 200 000 полиномов. . .
Расчёт переходных процессов в цепи постоянного тока
igorrr37 16.01.2026
/ * Дана цепь постоянного тока с R, L, C, k(ключ), U, E, J. Программа составляет систему уравнений по 1 и 2 законам Кирхгофа, решает её и находит переходные токи и напряжения на элементах схемы. . . .
Восстановить юзерскрипты Greasemonkey из бэкапа браузера
damix 15.01.2026
Если восстановить из бэкапа профиль Firefox после переустановки винды, то список юзерскриптов в Greasemonkey будет пустым. Но восстановить их можно так. Для этого понадобится консольная утилита. . .
Сукцессия микоризы: основная теория в виде двух уравнений.
anaschu 11.01.2026
https:/ / rutube. ru/ video/ 7a537f578d808e67a3c6fd818a44a5c4/
WordPad для Windows 11
Jel 10.01.2026
WordPad для Windows 11 — это приложение, которое восстанавливает классический текстовый редактор WordPad в операционной системе Windows 11. После того как Microsoft исключила WordPad из. . .
Classic Notepad for Windows 11
Jel 10.01.2026
Old Classic Notepad for Windows 11 Приложение для Windows 11, позволяющее пользователям вернуть классическую версию текстового редактора «Блокнот» из Windows 10. Программа предоставляет более. . .
Почему дизайн решает?
Neotwalker 09.01.2026
В современном мире, где конкуренция за внимание потребителя достигла пика, дизайн становится мощным инструментом для успеха бренда. Это не просто красивый внешний вид продукта или сайта — это. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru