Я использую библиотеку telethon для сканирования некоторых телеграммных каналов.Во время сканирования мне нужно разрешить много ссылок на соединения, имена пользователей и идентификаторы каналов.Чтобы разрешить эти элементы, я использовал метод client.get_entity()
, но через некоторое время серверы telegram заблокировали мой сканер для разрешения слишком большого числа имен пользователей.Я искал вокруг и нашел из этой проблемы , я должен использовать get_input_entity()
вместо get_entity()
.На самом деле telethon сохраняет сущности внутри локального файла SQLite, и всякий раз, когда выполняется вызов get_input_entity()
, он сначала ищет локальную базу данных SQLite, если не найдено совпадений, а затем отправляет запрос на серверы телеграмм.Пока все хорошо, но у меня есть две проблемы с этим подходом:
get_input_entity()
просто возвращает два атрибута: ID и хэш , но есть другие столбцынапример имя пользователя , телефон и имя в базе данных SQLite.Мне нужен метод, чтобы не просто возвращать ID и хэш , но и возвращать другие столбцы. - Мне нужно контролировать количество запросов на разрешение, отправленных на сервер телеграмм.но
get_input_entity()
отправляет запрос на серверы телеграмм, когда не находит совпадений в локальной базе данных.Проблема в том, что я не могу контролировать этот метод, когда запрашивать серверы телеграмм.На самом деле мне нужен логический аргумент для этого метода, указывающий, должен ли метод отправлять запрос серверам телеграмм, когда не найдено совпадений в локальной базе данных.
Я прочитал некоторые исходные коды телетона,в основном get_input_entity()
и написал свою собственную версию get_input_entity()
:
def my_own_get_input_entity(self, target, with_info: bool = False):
if self._client:
if target in ('me', 'self'):
return types.InputPeerSelf()
def get_info():
nonlocal self, result
res_id = 0
if isinstance(result, InputPeerChannel):
res_id = result.channel_id
elif isinstance(result, InputPeerChat):
res_id = result.chat_id
elif isinstance(result, InputPeerUser):
res_id = result.user_id
return self._sqlite_session._execute(
'select username, name from entities where id = ?', res_id
)
try:
result = self._client.session.get_input_entity(target)
info = get_info() if with_info else None
return result, info
except ValueError:
record_current_time()
try:
# when we are here, we are actually going to
# send request to telegram servers
if not check_if_appropriate_time_elapsed_from_last_telegram_request():
return None
result = self._client.get_input_entity(target)
info = get_info() if with_info else None
return result, info
except ChannelPrivateError:
pass
except ValueError:
pass
except Exception:
pass
Но мой код почему-то проблематичен с производительностью, потому что он делает избыточные запросы к базе данных SQLite.Например, если target
на самом деле является сущностью в локальной базе данных и with_info
равен True
, он сначала запрашивает локальную базу данных в строке self._client.session.get_input_entity(target)
и проверяет, является ли with_info
значение True
, а затем запрашиваетбазы данных снова, чтобы получить имя пользователя и имя столбцы.В другой ситуации, если target
не найден в локальной базе данных, вызов self._client.get_input_entity(target)
делает избыточный вызов к локальной базе данных.
Зная эти проблемы с производительностью, я углубился в исходные коды телемарафона, но, как и я,Я не знаю много о asyncio , я не смог бы написать лучше, чем указано выше.
Есть идеи, как решить проблемы?