我正在使用Telethon库来抓取一些电报频道。在爬行时,我需要解析许多加入链接、用户名和频道 ID。为了解决这些问题,我使用了方法client.get_entity()
,但过了一段时间,电报服务器禁止我的爬虫解析太多用户名。我四处搜索并从这个问题中发现,我应该使用get_input_entity()
而不是get_entity()
。实际上,telethon 将实体保存在本地 SQLite 文件中,每当调用时get_input_entity()
,它首先搜索本地 SQLite 数据库,如果没有找到匹配项,则向电报服务器发送请求。到目前为止一切顺利,但我对这种方法有两个问题:
get_input_entity()
只返回两个属性:ID和哈希,但 SQLite 数据库中还有其他列,例如username、phone和name。我需要一种方法,不仅要返回ID和hash,还要返回其他列。- 我需要控制发送到电报服务器的解析请求的数量,但
get_input_entity()
只要在本地数据库中找不到匹配项,就会向电报服务器发送请求。问题是我无法控制这种方法何时请求电报服务器。实际上,我需要此方法的布尔参数,指示当在本地数据库中找不到匹配项时,该方法是否应向电报服务器发送请求。
我阅读了一些 Telethon 源代码,主要是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)
调用会对本地数据库进行冗余调用。
了解了这些性能问题后,我深入研究了 telethon 源代码,但由于我对asyncio了解不多,所以我写不出比上面更好的代码了。
任何想法如何解决这些问题?