login.py 讲解
这个文件用于首次登录 Telegram,获取 Session String。
原始代码
import asyncio
from telethon import TelegramClient
from telethon.errors import SessionPasswordNeededError
from telethon.sessions import StringSession
from config import API_ID, API_HASH, PHONE, PASSWORD, PROXY
async def main():
print("=" * 50)
print("Telegram Userbot 登录工具")
print("=" * 50)
client = TelegramClient(
StringSession(),
API_ID,
API_HASH,
proxy=PROXY
)
await client.connect()
if await client.is_user_authorized():
print("已经登录!")
session_string = client.session.save()
print(f"\n你的 Session String:\n{session_string}\n")
print("请保存上面的 Session String 到 config.py 中")
else:
print(f"正在向 {PHONE} 发送验证码...")
try:
sent_code = await client.send_code_request(PHONE)
print("验证码已发送!")
print("- 检查 Telegram App 内通知")
print("- 检查短信")
print("- 等待语音电话")
code = input("\n请输入验证码: ").strip()
try:
await client.sign_in(PHONE, code, phone_code_hash=sent_code.phone_code_hash)
print("\n登录成功!")
session_string = client.session.save()
print(f"\n你的 Session String:\n{session_string}\n")
print("请保存上面的 Session String 到 config.py 中")
except SessionPasswordNeededError:
print("\n该账号开启了两步验证")
pwd = input("请输入两步验证密码: ").strip()
await client.sign_in(password=pwd)
session_string = client.session.save()
print(f"\n登录成功!\nSession String:\n{session_string}\n")
except Exception as e:
print(f"登录失败: {e}")
await client.disconnect()
if __name__ == "__main__":
asyncio.run(main())逐行讲解
第 1-4 行:导入模块
import asyncio
from telethon import TelegramClient
from telethon.errors import SessionPasswordNeededError
from telethon.sessions import StringSession拆解:
| 语句 | 说明 |
|---|---|
import asyncio |
导入 Python 内置的异步模块 |
from telethon import TelegramClient |
从 telethon 库导入 Telegram 客户端类 |
from telethon.errors import SessionPasswordNeededError |
导入特定的错误类型 |
from telethon.sessions import StringSession |
导入字符串会话类 |
telethon 是什么?
- 一个第三方 Telegram 客户端库
- 让你用代码控制 Telegram 账号
- 需要先安装:
pip install telethon
第 6 行:从 config 导入
from config import API_ID, API_HASH, PHONE, PASSWORD, PROXY- 从
config.py文件导入多个变量 - 这样就可以使用配置文件中的凭证
第 9 行:异步函数定义
async def main():关键概念:async def
def定义普通函数async def定义异步函数- 异步函数可以在等待网络请求时做其他事,不阻塞程序
为什么用异步?
- 网络操作很慢(可能需要几秒)
- 异步让程序在等待时可以处理其他任务
- 类似 JavaScript 的 Promise/async-await
第 10-12 行:打印分隔线
print("=" * 50)
print("Telegram Userbot 登录工具")
print("=" * 50)"=" * 50 是什么?
- Python 中字符串可以和数字相乘
- 结果是重复 50 次:
"==================================================" - 这是一个很实用的技巧
第 14-19 行:创建客户端
client = TelegramClient(
StringSession(),
API_ID,
API_HASH,
proxy=PROXY
)拆解:
TelegramClient(...)- 创建一个 Telegram 客户端实例StringSession()- 创建一个空的字符串会话(首次登录用)API_ID, API_HASH- 你的 API 凭证proxy=PROXY- 代理设置(可选参数,用参数名传递)
多行括号:
- Python 允许在括号内换行
- 这样代码更易读
第 21 行:连接服务器
await client.connect()await 是什么?
await表示"等待这个异步操作完成"- 只能在
async def函数内使用 - 程序会在这里暂停,直到连接成功或失败
流程:
调用 connect() → 等待网络连接 → 连接成功后继续第 23-28 行:检查是否已登录
if await client.is_user_authorized():
print("已经登录!")
session_string = client.session.save()
print(f"\n你的 Session String:\n{session_string}\n")
print("请保存上面的 Session String 到 config.py 中")逻辑:
is_user_authorized()- 检查是否已登录- 如果已登录,获取并打印 Session String
client.session.save()- 保存会话为字符串
f"\n..." 中的 \n:
\n是换行符- 在打印时会产生空行
第 29-59 行:未登录时的处理
else:
print(f"正在向 {PHONE} 发送验证码...")
try:
sent_code = await client.send_code_request(PHONE)
# ... 更多代码
except Exception as e:
print(f"登录失败: {e}")try-except 是什么?
- 尝试执行某些代码
- 如果出错,跳转到
except块处理 - 类似其他语言的
try-catch
流程图:
try:
发送验证码
↓
输入验证码
↓
登录
↓
成功!
except:
处理错误第 32 行:发送验证码请求
sent_code = await client.send_code_request(PHONE)- 向手机号发送验证码
- 返回的
sent_code包含验证码的哈希值(后续登录需要)
第 36-39 行:打印提示信息
print("验证码已发送!")
print("- 检查 Telegram App 内通知")
print("- 检查短信")
print("- 等待语音电话")简单的打印语句,提示用户在哪里查看验证码。
第 41 行:用户输入
code = input("\n请输入验证码: ").strip()input() 函数:
- 程序暂停,等待用户输入
- 用户按回车后,返回输入的字符串
.strip() 方法:
- 去除字符串首尾的空白字符
- 防止用户不小心输入了多余的空格
第 43-48 行:用验证码登录
try:
await client.sign_in(PHONE, code, phone_code_hash=sent_code.phone_code_hash)
print("\n登录成功!")
session_string = client.session.save()
print(f"\n你的 Session String:\n{session_string}\n")
print("请保存上面的 Session String 到 config.py 中")sign_in() 参数:
PHONE- 手机号code- 用户输入的验证码phone_code_hash- 发送验证码时返回的哈希值
第 50-56 行:处理两步验证
except SessionPasswordNeededError:
print("\n该账号开启了两步验证")
pwd = input("请输入两步验证密码: ").strip()
await client.sign_in(password=pwd)
session_string = client.session.save()
print(f"\n登录成功!\nSession String:\n{session_string}\n")逻辑:
- 如果账号开启了两步验证,
sign_in会抛出SessionPasswordNeededError - 捕获这个错误,要求用户输入密码
- 用密码再次尝试登录
第 58 行:断开连接
await client.disconnect()- 关闭与 Telegram 服务器的连接
- 这是良好的编程习惯:用完资源要释放
第 61-62 行:程序入口
if __name__ == "__main__":
asyncio.run(main())__name__ == "__main__" 是什么?
- 每个 Python 文件都有一个内置变量
__name__ - 如果直接运行这个文件,
__name__等于"__main__" - 如果是被其他文件导入,
__name__等于文件名
作用:
- 这段代码只在直接运行时执行
- 被导入时不会执行
asyncio.run(main()):
- 运行异步函数
main() asyncio.run()是启动异步程序的入口
执行流程图
开始
↓
打印标题
↓
创建 TelegramClient
↓
连接服务器 ──────→ 等待...
↓
已登录? ──是──→ 获取 Session String → 打印 → 结束
│
否
↓
发送验证码请求
↓
等待用户输入验证码
↓
尝试登录
↓
需要两步验证? ──是──→ 输入密码 → 登录
│
否
↓
获取 Session String
↓
打印
↓
断开连接
↓
结束关键知识点总结
| 概念 | 语法 | 说明 |
|---|---|---|
| 异步函数 | async def |
可以使用 await 的函数 |
| 等待异步操作 | await |
暂停直到操作完成 |
| 运行异步函数 | asyncio.run() |
程序入口 |
| 错误处理 | try-except |
捕获并处理异常 |
| 用户输入 | input() |
获取用户输入 |
| 字符串乘法 | "=" * 50 |
重复字符串 |
| 去空白 | .strip() |
去除首尾空白 |
练习
- 尝试运行这个文件:
python login.py - 思考:为什么网络操作要用
await? - 修改打印信息,添加你的名字