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

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

12.03.2020, 20:58. Показов 9664. Ответов 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
Ответ Создать тему
Новые блоги и статьи
модель ЗдравоСохранения 8. Подготовка к разному выполнению заданий
anaschu 08.04.2026
https:/ / github. com/ shumilovas/ med2. git main ветка * содержимое блока дэлэй из старой модели теперь внутри зайца новой модели 8ATzM_2aurI
Блокировка документа от изменений, если он открыт у другого пользователя
Maks 08.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа, разработанного в конфигурации КА2. Задача: запретить редактирование документа, если он открыт у другого пользователя. / / . . .
Система безопасности+живучести для сервера-слоя интернета (сети). Двойная привязка.
Hrethgir 08.04.2026
Далее были размышления о системе безопасности. Сообщения с наклонным текстом - мои. А как нам будет можно проверить, что ссылка наша, а не подделана хулиганами, которая выбросит на другую ветку и. . .
Модель ЗдрввоСохранения 7: больше работников, больше ресурсов.
anaschu 08.04.2026
работников и заданий может быть сколько угодно, но настроено всё так, что используется пока что только 20% kYBz3eJf3jQ
Дальние перспективы сервера - слоя сети с космологическим дизайном интефейса карты и логики.
Hrethgir 07.04.2026
Дальнейшее ближайшее планирование вывело к размышлениям над дальними перспективами. И вот тут может быть даже будут нужны оценки специалистов, так как в дальних перспективах всё может очень сильно. . .
Горе от ума
kumehtar 07.04.2026
Эта мне ментальная установка, что вот прямо сейчас, мол, мне для полного счастья не хватает (нужное вписать), и когда я этого достигну - тогда и полный кайф. Одна из самых сильных ловушек на пути. . . .
Использование значений реквизитов справочника в документе, с определенными условиями и правами
Maks 07.04.2026
1. Контроль срока действия договора Алгоритм из решения ниже реализован на примере нетипового документа "ЗаявкаНаРаботу", разработанного в конфигурации КА2. Задача: уведомлять пользователя, если. . .
Доступность команды формы по условию
Maks 07.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "СписаниеМатериалов", разработанного в конфигурации КА2. Задача: сделать доступной кнопку (команда формы "ЗавершитьСписание") при. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru