如何使用数字聊天ID来避免昂贵的`get_entity(channel_name)`调用?

huangapple go评论71阅读模式
英文:

How to use numeric chat IDs to avoid expensive `get_entity(channel_name)` calls?

问题

根据这个评论,我尝试在我的Telethon代码中使用数字通道ID,以避免通过昂贵的名称查找调用而使Telegram API受到限制,但我遇到了一些困难。

例如,假设我已经实例化并连接了client

messages = client.get_messages(numeric_channel_id)

...出现以下错误:

ValueError: 无法找到PeerUseruser_id=[numeric_channel_id])(PeerUser的输入实体

我认为这里发生了一些缓存,因为如果我首先使用帐户名称进行get_entity调用,然后get_messages调用就可以正常工作。也就是说,类似这样的操作:

client.get_entity(channel_name_which_belongs_to_numeric_channel_id)
messages = client.get_messages(numeric_channel_id)

这个方法运行正常,但现在我正在执行昂贵的get_entity(name)调用,这正是我试图避免的(因为它将导致FloodWaitError问题)。

在这种情况下,是否有任何方法可以使用通道的数字ID来避免昂贵的get_entity调用?

我还尝试过强制实体类型为通道,如下所示:

channel = Channel(id=numeric_channel_id, title=None, photo=None, date=None)
messages = client.get_messages(channel)

...但结果是相同的,只是错误中提到了PeerChannel而不是PeerUser

英文:

As per this comment, I'm trying to use numeric channel IDs in my telethon code, so that I don't end up spamming the Telegram API with expensive name lookup calls and getting throttled, but I'm having some difficulty.

e.g. assuming I've already instantiated and connected client:

messages = client.get_messages(numeric_channel_id)

...fails with this error:

ValueError: Could not find the input entity for PeerUser(user_id=[numeric_channel_id]) (PeerUser)

I think there's some cacheing going on, because if I do a get_entity call using the account name first, then the get_messages call works. i.e. something like this:

client.get_entity(channel_name_which_belongs_to_numeric_channel_id)
messages = client.get_messages(numeric_channel_id)

That works just fine, but now I'm doing the expensive get_entity(name) call which is what I'm trying to avoid (because it will result in FloodWaitError problems).

Is there any way I can use the numeric ID of a channel to avoid the expensive get_entity call, in this scenario?


I've also tried forcing the entity type to Channel, like this:

channel = Channel(id=numeric_channel_id, title=None, photo=None, date=None)
messages = client.get_messages(channel)

...but the results are the same, except that the error mentions PeerChannel rather than PeerUser

答案1

得分: 1

ID使用不会生效,除非您像您所说的那样缓存了目标,这是使用整数ID的唯一方法。

您必须已经通过事件或手动请求(例如,获取用户名)遇到了实体。

您应该使用client.get_input_entity('username')

它会首先尝试在本地缓存中搜索已保存的ID +哈希,以查找与传递的用户名相等的内容,如果找到,它将不会执行ResolveUsername(较重的操作),而是使用本地的access_hash + ID,并返回一个inputPeer。然后,您可以将其传递给您想要的任何请求。

除非您确定已经遇到了其持有者,否则不能仅仅使用ID,换句话说,您使用的ID必须是您在库内并在同一会话中找到的,而不是您从外部获知的东西。

没有通过ID来获取某些内容的神奇方式,如果您确实知道它,那么库必须在存在access_hash时创建一个InputPeer

英文:

ID usage is not going to work unless you cached the target as you stated, that's the only way to use the integer id.

you must have met the entity from events or manual requests (say, username fetching).

you should be using client.get_input_entity('username')

it will try to search the local cache first for the saved id + hash that equals the passed username, if found it won't do ResolveUsername (heavy one) and use the local access_hash + id and return you an inputPeer. you pass that to any request you want.

you mustn't use id alone unless you're certain you have met its holder, in other words, id you use has to be something you found out from within the library and within the same session, not something you knew/found out externally.

There is no magical way to fetch something with id you claim you know, if you actually know it, the lib has to create (when the access_hash is present) an InputPeer

答案2

得分: 1

如另一个答案所述,按用户名获取数据始终有效但代价高昂。但请注意,这种调用会填充缓存,因此稍后可以通过ID更便宜地再次获取。

如果您确实需要对某个实体进行稳定引用,不能依赖会话缓存,并且希望避免使用用户名,可以参考实体与输入实体的文档可能会有所帮助。

归根结底,您可以这样做:

print(await client.get_input_entity('username'))

...这将显示类似于以下内容:

InputPeerChannel(channel_id=1066197625, access_hash=-6302373944955169144)

...然后,调用get_input_entity的帐户将始终能够使用打印出的结果,无需将其放入缓存中:

from telethon.tl.types import InputPeerChannel

USERNAME = InputPeerChannel(channel_id=1066197625, access_hash=-6302373944955169144)

# ...

await client.send_message(USERNAME, 'Hi')  # 不需要缓存即可正常工作
英文:

As the other answer states, fetching by username will always work but is expensive. However note that such a call will fill the cache so it can later be fetched again much more cheaply by ID.

If you really need a stable reference to some entity and cannot rely on the session cache, and want to avoid usernames, the documentation for Entities vs. Input Entities may be helpful.

What it boils down to is, you can do this:

print(await client.get_input_entity('username'))

...which will show something like:

InputPeerChannel(channel_id=1066197625, access_hash=-6302373944955169144)

...and then, the account that made the get_input_entity call will always be able to use the printed result, without the need for it to be in cache:

from telethon.tl.types import InputPeerChannel

USERNAME = InputPeerChannel(channel_id=1066197625, access_hash=-6302373944955169144)

# ...

await client.send_message(USERNAME, 'Hi')  # works without cache

huangapple
  • 本文由 发表于 2023年1月9日 11:07:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/75052844.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定