引言
在Telegram机器人开发中,接收用户发送的联系人卡片(Contact)是一种常见的需求。例如,用户通过机器人分享自己的手机号或他人名片,机器人需要提取其中的信息并保存到数据库,用于用户认证、CRM系统或自动回复等场景。本文将从Telegram Bot API的基础出发,详细讲解联系人卡片的消息格式、获取方式、字段解析以及存储策略,并提供可直接运行的Python代码示例。
1. 理解Telegram联系人卡片消息格式
Telegram中的联系人卡片本质上是一条Message,其类型为contact。根据Bot API文档,联系人消息包含以下字段:
phone_number:必填,对方的电话号码,字符串格式,可能包含国际区号。first_name:必填,联系人的名字。last_name:可选,联系人的姓氏。user_id:可选,如果联系人是一个Telegram用户,则包含其用户ID。vcard:可选,一个vCard格式的字符串,包含完整的联系人信息,可能有额外字段。
收到联系人消息时,update.message.contact对象即包含这些数据。需要注意的是,机器人只能接收用户主动发送的联系人卡片,且用户无法通过机器人主动获取另一个用户的电话(除非该用户直接发送)。
2. 使用Bot API获取联系人消息
机器人获取消息的方式有两种:长轮询(getUpdates)和Webhook。本文以长轮询为例,适合开发测试和低流量场景。核心代码如下:
import requests
import time
TOKEN = "YOUR_BOT_TOKEN"
URL = f"https://api.telegram.org/bot"
def get_updates(offset=None):
params = {"timeout": 30, "offset": offset}
resp = requests.get(URL + "/getUpdates", params=params)
return resp.json()
last_update_id = 0
while True:
data = get_updates(last_update_id + 1)
if data["ok"]:
for update in data["result"]:
message = update.get("message")
if message and message.get("contact"):
# 处理联系人消息
handle_contact(message["chat"]["id"], message["contact"])
last_update_id = update["update_id"]
time.sleep(1)3. 提取联系人信息字段
收到联系人对象后,可以轻松提取所有字段。下面是一个提取函数,它会返回一个字典,供后续存储使用:
def handle_contact(chat_id, contact):
contact_info = {
"phone_number": contact.get("phone_number"),
"first_name": contact.get("first_name"),
"last_name": contact.get("last_name", ""),
"user_id": contact.get("user_id"),
"vcard": contact.get("vcard", "")
}
# 在此处调用保存函数
save_contact(chat_id, contact_info)注意:如果联系人消息带有vcard字段,它包含更丰富的结构化数据(如组织、地址、邮箱等),可以通过标准vCard解析库进一步拆分。但对于大多数场景,phone_number和first_name已足够。
4. 保存联系人信息的策略
根据应用需求,可以选择不同的存储方案:
- 数据库存储:推荐使用SQLite或PostgreSQL。表结构至少包含
id,chat_id,phone_number,first_name,last_name,user_id,vcard,created_at字段。这样便于检索和管理。 - 文件存储:如果数据量小,可以直接保存为JSON或CSV文件。但考虑并发和安全性,不建议生产环境使用。
- 云服务:如Google Sheets或Airtable,适合非程序员快速集成。
以下是使用SQLite的保存示例:
import sqlite3
def save_contact(chat_id, contact_info):
conn = sqlite3.connect("contacts.db")
c = conn.cursor()
c.execute('''CREATE TABLE IF NOT EXISTS contacts
(id INTEGER PRIMARY KEY AUTOINCREMENT,
chat_id INTEGER,
phone_number TEXT,
first_name TEXT,
last_name TEXT,
user_id INTEGER,
vcard TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP)''')
c.execute("INSERT INTO contacts (chat_id, phone_number, first_name, last_name, user_id, vcard) VALUES (?,?,?,?,?,?)",
(chat_id, contact_info["phone_number"], contact_info["first_name"], contact_info["last_name"], contact_info["user_id"], contact_info["vcard"]))
conn.commit()
conn.close()5. 完整代码示例(Python)
结合以上片段,下面是一个完整的可运行机器人程序,它接收联系人消息,保存到SQLite,并回复确认信息。
import requests
import sqlite3
import time
TOKEN = "YOUR_BOT_TOKEN"
URL = f"https://api.telegram.org/bot"
def get_updates(offset=None):
params = {"timeout": 30, "offset": offset}
resp = requests.get(URL + "/getUpdates", params=params)
return resp.json()
def save_contact(chat_id, contact_info):
conn = sqlite3.connect("contacts.db")
c = conn.cursor()
c.execute('''CREATE TABLE IF NOT EXISTS contacts
(id INTEGER PRIMARY KEY AUTOINCREMENT,
chat_id INTEGER,
phone_number TEXT,
first_name TEXT,
last_name TEXT,
user_id INTEGER,
vcard TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP)''')
c.execute("INSERT INTO contacts (chat_id, phone_number, first_name, last_name, user_id, vcard) VALUES (?,?,?,?,?,?)",
(chat_id, contact_info["phone_number"], contact_info["first_name"], contact_info["last_name"], contact_info["user_id"], contact_info["vcard"]))
conn.commit()
conn.close()
def handle_contact(chat_id, contact):
contact_info = {
"phone_number": contact.get("phone_number"),
"first_name": contact.get("first_name"),
"last_name": contact.get("last_name", ""),
"user_id": contact.get("user_id"),
"vcard": contact.get("vcard", "")
}
save_contact(chat_id, contact_info)
# 发送确认消息
text = f"已保存联系人:{contact_info['first_name']} {contact_info['last_name']}\n电话:{contact_info['phone_number']}"
requests.post(URL + "/sendMessage", json={"chat_id": chat_id, "text": text})
last_update_id = 0
while True:
data = get_updates(last_update_id + 1)
if data["ok"]:
for update in data["result"]:
message = update.get("message")
if message and message.get("contact"):
handle_contact(message["chat"]["id"], message["contact"])
last_update_id = update["update_id"]
time.sleep(1)6. 注意事项与最佳实践
- 隐私保护:联系人信息属于敏感数据,存储时必须加密并遵守相关法规(如GDPR)。建议只保存业务所需字段,并在不需要时及时删除。
- 权限控制:只允许特定用户或群组发送联系人,防止垃圾信息。可以通过检查
chat_id白名单实现。 - 错误处理:实际开发中应为网络异常、数据库错误等添加try/except,并记录日志。
- 消息去重:Telegram更新可能重复,使用
update_id递增偏移可避免,但更稳妥的方案是记录消息ID。 - Webhook模式:生产环境建议使用Webhook替代轮询,以减少延迟和服务器负载。
- 验证数据:提取字段时默认值处理要谨慎,尤其是
user_id可能为None。
总结
通过本文,你已经掌握了Telegram机器人接收联系人卡片并保存信息的完整流程。从解析消息格式到使用SQLite持久化,再到代码实现,这套方案可以直接应用于实际项目。记住,在处理用户数据时,安全与隐私永远是第一位的。希望这篇教程能帮助你构建更强大的Telegram机器人。