Web 登录¶
概述¶
igapi.WebClient 是面向 Instagram Web 私有 API 的客户端类。相比 Client(Android),它模拟浏览器行为,使用 CSRF Token 进行请求验证,并原生支持双因素认证(2FA)的全自动和半自动两种模式。
适用场景:
- 账号开启了双因素认证(TOTP 或 SMS)
- 需要调用 Web 独有端点(如 GraphQL 帖子查询)
- 模拟浏览器访问行为的场合
快速开始¶
import asyncio
import igapi
async def main():
# 1. 创建 Web 客户端
web = igapi.WebClient()
# 2. 登录(无 2FA 账号)
await web.login("your_username", "your_password")
# 3. 确认登录状态
print(await web.is_logged_in()) # True
# 4. 导出 session
session_str = web.export_account_string()
asyncio.run(main())
WebClient 构造参数¶
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
proxy |
str \| None |
None |
HTTP 代理地址,格式 http://host:port |
danger_accept_invalid_certs |
bool |
False |
跳过 TLS 证书验证,配合抓包代理使用 |
http1_only |
bool |
False |
强制使用 HTTP/1.1,配合部分抓包代理使用 |
account |
AccountInfo \| None |
None |
传入已有的 AccountInfo 对象恢复 session,平台类型必须是 "web" |
注意:向
WebClient传入 Android 平台的AccountInfo会导致初始化失败并抛出ValueError。请确保AccountInfo.platform属性为"web"。
login() 详解¶
三种登录模式¶
WebClient.login() 根据是否传入 two_fa_secret 以及账号是否开启 2FA,自动切换三种工作模式。
模式一:普通登录(无 2FA)¶
账号未开启双因素认证时,直接调用即可:
模式二:自动 2FA(传入 TOTP secret)¶
账号开启了基于 TOTP(如 Google Authenticator)的 2FA,且你拥有绑定时的 Base32 密钥:
await web.login(
"your_username",
"your_password",
two_fa_secret="JBSWY3DPEHPK3PXP", # Base32 编码的 TOTP 密钥
)
# 库会自动生成当前 6 位验证码并完成 2FA,无需任何手动干预
模式三:手动 2FA(捕获异常后输入验证码)¶
账号开启了 2FA 但未提供 secret(或使用 SMS 验证码),捕获 TwoFactorRequired 后调用 verify_two_factor():
try:
await web.login("your_username", "your_password")
except igapi.TwoFactorRequired as e:
# 可以从 e.two_factor_info 判断 2FA 方式
code = input("请输入 6 位验证码(TOTP 或 SMS): ")
await web.verify_two_factor(code)
完整参数表¶
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
username |
str |
必填 | Instagram 用户名 |
password |
str |
必填 | 账号密码 |
two_fa_secret |
str \| None |
None |
TOTP 密钥(Base32 编码)。传入后自动完成 2FA |
可能抛出的异常¶
| 异常类型 | 说明 |
|---|---|
igapi.TwoFactorRequired |
账号需要 2FA 且未传入 two_fa_secret |
igapi.ChallengeRequired |
需要完成安全挑战 |
ValueError |
密码错误、用户名无效或 TOTP secret 格式错误 |
PermissionError |
账号被锁定 |
ConnectionError |
网络错误 |
verify_two_factor()¶
方法签名¶
说明¶
当 login() 抛出 TwoFactorRequired 后,调用此方法输入用户提供的验证码完成登录。
内部会自动复用 login() 调用时暂存的用户名、密码和 2FA 标识符,无需再次传入。
参数¶
| 参数 | 类型 | 说明 |
|---|---|---|
code |
str |
6 位验证码,可以是 TOTP 或 SMS 验证码 |
可能抛出的异常¶
| 异常类型 | 说明 |
|---|---|
RuntimeError |
未先调用 login() 或 login() 未触发 2FA,直接调用此方法时抛出 |
ValueError |
验证码错误 |
重要:
verify_two_factor()必须在同一个WebClient实例上,且紧接着login()抛出TwoFactorRequired之后调用。如果创建了新的WebClient实例,登录上下文会丢失。
登录流程图¶
flowchart TD
A[调用 web.login] --> B{服务端返回}
B -->|登录成功| C[登录完成]
B -->|TwoFactorRequired| D{是否提供 two_fa_secret}
B -->|其他错误| E[抛出对应异常]
D -->|是| F[自动生成 TOTP 验证码]
F --> G[调用 web_two_factor_login]
G -->|成功| C
G -->|失败| H[抛出 ValueError 验证码错误]
D -->|否| I[暂存登录上下文]
I --> J[抛出 TwoFactorRequired]
J --> K[用户调用 verify_two_factor 输入验证码]
K --> G
完整示例¶
场景一:无 2FA 账号¶
import asyncio
import igapi
async def main():
web = igapi.WebClient()
try:
await web.login("your_username", "your_password")
print("登录成功,用户:", web.export_account().username)
except ValueError as e:
print(f"凭证错误: {e}")
except ConnectionError as e:
print(f"网络错误: {e}")
asyncio.run(main())
场景二:自动 TOTP 2FA¶
import asyncio
import igapi
import os
async def main():
web = igapi.WebClient()
await web.login(
os.environ["IG_USERNAME"],
os.environ["IG_PASSWORD"],
two_fa_secret=os.environ["IG_TOTP_SECRET"], # Base32 密钥
)
print("自动 2FA 登录成功")
session_str = web.export_account_string()
asyncio.run(main())
场景三:手动 SMS 或 TOTP 验证码¶
import asyncio
import igapi
async def main():
web = igapi.WebClient()
try:
await web.login("your_username", "your_password")
print("登录成功(无 2FA)")
except igapi.TwoFactorRequired as e:
info = e.two_factor_info
# 根据 2FA 信息判断验证方式
if info.get("sms_two_factor_on"):
print("请查收 SMS 验证码")
elif info.get("totp_two_factor_on"):
print("请打开 Authenticator 应用")
else:
print("请输入验证码")
code = input("验证码: ").strip()
try:
await web.verify_two_factor(code)
print("2FA 验证成功,已登录")
except ValueError as e:
print(f"验证码错误: {e}")
except igapi.ChallengeRequired as e:
print("需要完成安全挑战:", e.challenge_info.get("checkpoint_url"))
except PermissionError as e:
print(f"账号受限: {e}")
asyncio.run(main())
场景四:使用 session 恢复避免重复登录¶
import asyncio
import igapi
import os
SESSION_FILE = "web_session.txt"
async def get_web_client() -> igapi.WebClient:
if os.path.exists(SESSION_FILE):
with open(SESSION_FILE) as f:
saved = f.read().strip()
try:
account = igapi.AccountInfo.parse(saved, platform="web")
web = igapi.WebClient(account=account)
if await web.is_logged_in():
return web
except Exception:
pass # session 已失效,重新登录
web = igapi.WebClient()
await web.login(
os.environ["IG_USERNAME"],
os.environ["IG_PASSWORD"],
two_fa_secret=os.environ.get("IG_TOTP_SECRET"),
)
with open(SESSION_FILE, "w") as f:
f.write(web.export_account_string())
return web
async def main():
web = await get_web_client()
asyncio.run(main())
与 Android Client 的差异¶
| 对比项 | Client(Android) |
WebClient(Web) |
|---|---|---|
| 模拟平台 | Instagram Android App | Instagram Web 浏览器 |
| API 端点 | i.instagram.com/api/v1 |
www.instagram.com/api/v1 |
| 请求签名 | HMAC-SHA256 signed_body |
X-CSRFToken 请求头 |
| 密码加密 | RSA + AES-GCM | RSA |
| 2FA 支持 | 不支持(抛出异常) | 支持自动/手动两种模式 |
| GraphQL 帖子查询 | 不支持 | 支持 |
| session 字符串平台标记 | android |
web |
| AccountInfo 设备字段 | android_id, phone_id, uuid, device_id |
csrf_token |
注意事项¶
-
2FA secret 保护:TOTP 密钥(
two_fa_secret)等同于账号控制权,请通过环境变量或加密存储传入,不要硬编码在代码中。 -
verify_two_factor 的时间限制:TOTP 验证码每 30 秒刷新一次,SMS 验证码通常有效期为 10 分钟。
verify_two_factor()调用必须在验证码有效期内完成。 -
同一实例不可复用登录上下文:
verify_two_factor()依赖login()暂存的内部状态,仅在同一WebClient实例上有效。重新创建实例后需要重新调用login()。 -
Web session 不能给 Android Client 使用:
AccountInfo的平台类型与客户端类型必须匹配,否则初始化时会抛出ValueError。
常见问题¶
Q: login() 传了 two_fa_secret 但仍然抛出 TwoFactorRequired,是什么原因?
A: 不会发生这种情况。当传入 two_fa_secret 时,库会在内部捕获 TwoFactorRequired 并自动完成 TOTP 验证,不会将该异常向上传播。如果抛出的是 ValueError,说明 TOTP secret 格式错误或验证码验证失败。
Q: TOTP secret 从哪里获取?
A: 在 Instagram 中开启双因素认证时,会展示一个 Base32 格式的密钥(通常是形如 JBSWY3DPEHPK3PXP 的字符串),这就是需要传入的 two_fa_secret。如果当时没有保存该密钥,只能重新在账号安全设置中关闭并重新开启 2FA 获取新的密钥。
Q: 使用 SMS 验证码时如何自动化?
A: SMS 验证码无法预先自动生成,必须通过手动模式(捕获 TwoFactorRequired 后由用户输入)。如果需要完全自动化,建议将账号 2FA 方式改为 TOTP,这样可以使用 two_fa_secret 实现全自动登录。
Q: WebClient 和 Client 可以共用同一个 session 字符串吗?
A: 不可以。Web 和 Android 的 session 字符串格式不同(设备信息字段不同),且 AccountInfo.parse() 需要明确指定 platform。两者的 session 互不通用。
Q: 调用 verify_two_factor() 时报 RuntimeError: 请先调用 login(),如何解决?
A: 确保以下两点:一是在同一个 WebClient 实例上先调用了 login(),二是 login() 确实抛出了 TwoFactorRequired(而不是成功返回或抛出其他异常)。如果实例被重新创建,需要重新从 login() 开始。