Получить имя пользователя из локальной сессии Telethon - PullRequest
0 голосов
/ 12 сентября 2018

Я использую библиотеку telethon для сканирования некоторых телеграммных каналов.Во время сканирования мне нужно разрешить много ссылок на соединения, имена пользователей и идентификаторы каналов.Чтобы разрешить эти элементы, я использовал метод client.get_entity(), но через некоторое время серверы telegram заблокировали мой сканер для разрешения слишком большого числа имен пользователей.Я искал вокруг и нашел из этой проблемы , я должен использовать get_input_entity() вместо get_entity().На самом деле telethon сохраняет сущности внутри локального файла SQLite, и всякий раз, когда выполняется вызов get_input_entity(), он сначала ищет локальную базу данных SQLite, если не найдено совпадений, а затем отправляет запрос на серверы телеграмм.Пока все хорошо, но у меня есть две проблемы с этим подходом:

  1. get_input_entity() просто возвращает два атрибута: ID и хэш , но есть другие столбцынапример имя пользователя , телефон и имя в базе данных SQLite.Мне нужен метод, чтобы не просто возвращать ID и хэш , но и возвращать другие столбцы.
  2. Мне нужно контролировать количество запросов на разрешение, отправленных на сервер телеграмм.но 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 , я не смог бы написать лучше, чем указано выше.

Есть идеи, как решить проблемы?

1 Ответ

0 голосов
/ 14 сентября 2018

client.session.get_input_entity не будет вызывать API (он не может) и завершится ошибкой, если в локальной базе данных нет совпадений, что, вероятно, и является желаемым поведением.

На данный момент вы можете получить доступ к приватному атрибуту client.session._conn. Это sqlite3.Connection объект, поэтому вы можете использовать его для выполнения всех запросов. Обратите внимание, что это может привести к поломке, так как вы получаете доступ к приватному члену, хотя никаких изменений в ближайшее время не ожидается В идеале, вы должны создать подкласс файла сессии в соответствии с вашими потребностями. См. Файлы сессий в документации.

...