跳转至

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)

账号未开启双因素认证时,直接调用即可:

await web.login("your_username", "your_password")

模式二:自动 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()

方法签名

await web.verify_two_factor(code: str) -> None

说明

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: WebClientClient 可以共用同一个 session 字符串吗?

A: 不可以。Web 和 Android 的 session 字符串格式不同(设备信息字段不同),且 AccountInfo.parse() 需要明确指定 platform。两者的 session 互不通用。

Q: 调用 verify_two_factor() 时报 RuntimeError: 请先调用 login(),如何解决?

A: 确保以下两点:一是在同一个 WebClient 实例上先调用了 login(),二是 login() 确实抛出了 TwoFactorRequired(而不是成功返回或抛出其他异常)。如果实例被重新创建,需要重新从 login() 开始。