Python 3.x 从本地会话Telethon获取用户名

Python 3.x 从本地会话Telethon获取用户名,python-3.x,telegram,telethon,Python 3.x,Telegram,Telethon,我正在利用图书馆搜寻一些电报频道。在爬网时,我需要解析许多连接链接、用户名和通道ID。为了解决这些问题,我使用了方法client.get_entity(),但过了一段时间,电报服务器因为解决了太多的用户名而禁止了我的爬虫程序。我四处搜索发现,我应该使用get\u input\u entity()而不是get\u entity()。实际上,telethon将实体保存在本地SQLite文件中,每当调用get\u input\u entity()时,它首先搜索本地SQLite数据库,如果没有找到匹配项

我正在利用图书馆搜寻一些电报频道。在爬网时,我需要解析许多连接链接、用户名和通道ID。为了解决这些问题,我使用了方法
client.get_entity()
,但过了一段时间,电报服务器因为解决了太多的用户名而禁止了我的爬虫程序。我四处搜索发现,我应该使用
get\u input\u entity()
而不是
get\u entity()
。实际上,telethon将实体保存在本地SQLite文件中,每当调用
get\u input\u entity()
时,它首先搜索本地SQLite数据库,如果没有找到匹配项,则向电报服务器发送请求。到目前为止还不错,但这种方法有两个问题:

  • get\u input\u entity()
    只返回两个属性:ID和hash,但SQLite数据库中还有其他列,如username、phone和name。我需要一个方法,不仅返回ID和hash,还返回其他列
  • 我需要控制发送到电报服务器的解析请求的数量,但只要在本地数据库中发现不匹配,就会向电报服务器发送请求。问题是我无法控制这种方法何时请求电报服务器。实际上,对于这个方法,我需要一个布尔参数,指示当本地数据库中找不到匹配项时,该方法是否应该向电报服务器发送请求
  • 我阅读了一些telethon源代码,主要是
    get\u input\u entity()
    ,并编写了自己版本的
    get\u input\u entity()

    但我的代码在某种程度上存在性能问题,因为它对SQLite数据库进行了冗余查询。例如,如果
    target
    实际上是本地数据库中的一个实体,并且
    with\u info
    True
    ,则它首先在
    self.\u client.session.get\u input\u entity(target)
    行中查询本地数据库,并检查
    with\u info
    是否是
    True
    ,然后再次查询数据库以获取用户名和名称列。在另一种情况下,如果在本地数据库中找不到
    target
    ,则调用
    self.\u client.get\u input\u entity(target)
    对本地数据库进行冗余调用

    了解了这些性能问题后,我深入研究了telethon源代码,但由于我对asyncio了解不多,因此我无法编写比上述更好的代码


    有没有解决问题的方法?

    client.session.get\u input\u entity将不进行API调用(它不能),如果本地数据库中没有匹配项,则将失败,这可能是您想要的行为

    现在,您可以访问
    client.session.\u conn
    private属性。它是一个
    sqlite3.Connection
    对象,因此您可以使用它来进行所有需要的查询。请注意,这很容易中断,因为您正在访问一个私有成员,尽管预计不久不会有任何更改。理想情况下,您应该对会话文件进行子类化,以满足您的需要。请参阅文档中的

    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