在使用Telegram机器人时,用户可能会因为各种原因屏蔽机器人,比如认为消息打扰、不再需要服务等。当用户屏蔽机器人后,机器人将无法主动向该用户发送消息,也无法获取用户的在线状态等信息。那么,机器人如何知道用户已经屏蔽了自己呢?本文将介绍两种最有效的方法,并提供完整的Python代码示例。
一、检测屏蔽的原理
Telegram Bot API并没有提供一个直接的“查询是否被屏蔽”的方法,但我们可以通过间接手段来判断:
- 主动检测:尝试向用户发送消息,根据返回的错误状态判断。
- 被动监听:监听Telegram发送的
my_chat_member更新,从中获取用户屏蔽机器人的事件。
这两种方法各有适用场景,建议开发者根据实际需求选择或组合使用。
二、方法一:主动发送消息检测
这是最直观的方法。机器人向目标用户发送一条消息(例如“Are you still there?”),如果用户已经屏蔽了机器人,Telegram API会返回HTTP 403错误,错误描述为“Forbidden: bot was blocked by the user”。我们只需要捕获这个错误,就能确认用户已屏蔽机器人。
Python实现(使用requests直接调用Bot API)
import requests
import time
def check_user_blocked(bot_token, chat_id):
url = f"https://api.telegram.org/bot/sendMessage"
payload = {
"chat_id": chat_id,
"text": "ping"
}
try:
response = requests.post(url, json=payload, timeout=10)
if response.status_code == 200:
return False # 消息发送成功,用户未屏蔽
elif response.status_code == 403:
data = response.json()
if data['description'] == 'Forbidden: bot was blocked by the user':
return True # 用户已屏蔽
else:
# 其他403原因,例如群组权限不足
return False
else:
# 其他错误,如网络问题或速率限制
print(f"Unexpected error: {response.status_code}")
return False
except Exception as e:
print(f"Request failed: ")
return False
# 使用示例
token = "YOUR_BOT_TOKEN"
user_chat_id = 123456789
if check_user_blocked(token, user_chat_id):
print("用户已屏蔽机器人")
else:
print("用户未屏蔽或消息正常发送")
使用python-telegram-bot库
from telegram import Bot
from telegram.error import Forbidden
async def is_blocked(bot, chat_id):
try:
await bot.send_message(chat_id=chat_id, text="ping")
return False
except Forbidden as e:
if "blocked by the user" in str(e):
return True
else:
return False
except Exception as e:
print(f"其他错误: ")
return False
注意:主动检测会向用户发送一条消息,如果频繁检测可能引起用户反感,甚至被举报。因此,建议仅在必要时使用,比如用户超过一定天数未活动时。
三、方法二:监听my_chat_member更新(被动检测)
Telegram提供了my_chat_member更新,每当机器人与某个用户之间的状态发生变化时(例如用户屏蔽机器人、取消屏蔽、机器人被加入群组等),Bot API都会推送一个包含my_chat_member字段的Update。
我们只需解析更新中的new_chat_member.status,如果状态为`kicked`,说明用户屏蔽了机器人;如果状态变为`member`(或`new_chat_member`),则说明用户取消了屏蔽。
使用python-telegram-bot库处理
from telegram.ext import Application, ChatMemberHandler
def on_my_chat_member(update, context):
new_status = update.my_chat_member.new_chat_member.status
user_id = update.my_chat_member.from_user.id
if new_status == 'kicked':
print(f"用户 屏蔽了机器人")
elif new_status == 'member':
print(f"用户 解除了屏蔽")
# 创建Application并注册处理器
def main():
application = Application.builder().token("YOUR_BOT_TOKEN").build()
application.add_handler(ChatMemberHandler(on_my_chat_member, ChatMemberHandler.MY_CHAT_MEMBER))
application.run_polling()
if __name__ == '__main__':
main()
使用node-telegram-bot-api(Node.js)
const TelegramBot = require('node-telegram-bot-api');
const bot = new TelegramBot('YOUR_BOT_TOKEN', {polling: true});
bot.on('my_chat_member', (msg) => {
const newStatus = msg.my_chat_member.new_chat_member.status;
const userId = msg.my_chat_member.from.id;
if (newStatus === 'kicked') {
console.log(`用户 $ 屏蔽了机器人`);
} else if (newStatus === 'member') {
console.log(`用户 $ 解除了屏蔽`);
}
});
被动检测的优势在于实时、无打扰,且不需要知道用户的chat_id(更新中包含chat信息)。但需要确保机器人持续运行(如使用Webhook或长轮询),且处理程序能够及时响应。对于需要记录屏蔽状态的场景,建议将状态存储到数据库,避免重复处理。
四、方法对比与注意事项
| 对比项 | 主动发送消息 | 监听my_chat_member |
|---|---|---|
| 实时性 | 低(需要触发检测) | 高(实时推送) |
| 打扰性 | 有(发送消息) | 无 |
| 要求 | 需要用户chat_id | 无需额外参数,但需持续监听 |
| 可靠性 | 较高(403错误明确) | 高(事件驱动) |
| 适用场景 | 定期清理失效用户 | 实时更新用户状态 |
注意事项:
- 主动检测时,应控制频率,避免触发Bot API的速率限制。
- 监听my_chat_member时,需要处理来自群组、频道等不同chat类型的更新,本文章只涉及与用户的私聊。
- 若机器人同时运行多个实例,要防止重复处理,建议结合数据库唯一索引。
- 用户屏蔽机器人后,机器人无法通过API获取用户的更多信息(如Profile照片),但之前缓存的数据仍可使用。
五、总结
检测用户是否屏蔽Telegram机器人,虽然没有直接的方法,但通过主动发送消息或监听my_chat_member事件,我们可以准确、及时地掌握用户状态。主动方法适合周期性清理,被动方法适合实时响应。在实际开发中,建议优先采用被动监听,以减少不必要的消息打扰,并提高效率。
希望本教程能帮助你的Telegram机器人更智能地管理用户关系,提升用户体验。