跳转至

图片上传(UploadApi)

1. 概述

UploadApi 提供底层图片上传能力,将图片数据上传到 Instagram 的上传服务器,返回 upload_id,用于后续的发帖配置(configure)步骤。

UploadApi 支持 Android 端Web 端 两条路径:

  • Android 端photo() + configure()):通过 ClientWebClient 均可构造,使用 Android 移动端上传协议,支持 location_id 位置标签
  • Web 端photo_web() + configure_web()):仅限 WebClient 构造的 UploadApi 实例,使用 Web rupload 协议,需要额外提供图片尺寸

在大多数发帖场景中,如果使用 Web 平台,推荐直接使用 PostApi.create_photo()(一步完成上传 + 发布)。UploadApi 适合以下高级场景:

  • 在上传和发布之间插入自定义逻辑(如进度显示)
  • 使用 Android 平台客户端发帖
  • 需要添加 location_id 位置标签

说明UploadApi 本身只负责上传,不会发布帖子。上传完成后需要调用 configure()configure_web() 才能将图片发布为帖子。


2. 快速开始

Android 端上传并发布

import asyncio
import igapi

async def main():
    account = igapi.AccountInfo.parse("用户名:密码||设备信息|cookies||")
    client = igapi.Client(account=account)

    upload_api = igapi.UploadApi(client)

    with open("photo.jpg", "rb") as f:
        image_data = f.read()

    # 步骤 1:上传图片
    result = await upload_api.photo(image_data)
    print(f"上传成功,upload_id: {result.upload_id}")

    # 步骤 2:配置并发布
    media = await upload_api.configure(
        upload_id=result.upload_id,
        caption="第一张通过 igapi 发布的照片"
    )
    print(f"发帖成功,帖子 ID: {media.id}")

asyncio.run(main())

Web 端上传并发布

import asyncio
import igapi

async def main():
    account = igapi.AccountInfo.parse("用户名:密码||设备信息|cookies||", platform="web")
    web = igapi.WebClient(account=account)

    upload_api = igapi.UploadApi(web)

    with open("photo.jpg", "rb") as f:
        image_data = f.read()

    # Web 端上传需要提供尺寸
    result = await upload_api.photo_web(image_data, width=1080, height=1080)
    print(f"Web 上传成功,upload_id: {result.upload_id}")

    # Web 端配置发布
    media = await upload_api.configure_web(
        upload_id=result.upload_id,
        caption="Web 端发布的照片"
    )
    print(f"发帖成功,帖子 ID: {media.id}")

asyncio.run(main())

3. API 参考

3.1 UploadApi(client)

构造 UploadApi 实例。

签名

igapi.UploadApi(client: Client | WebClient) -> UploadApi

参数

参数 类型 必填 说明
client Client \| WebClient Android 平台客户端或 Web 平台客户端均可

说明

构造时传入的客户端类型决定了哪些方法可用:

  • 传入 Client(Android):可调用 photo()configure();调用 photo_web()configure_web() 会抛出 TypeError
  • 传入 WebClient:全部四个方法均可调用

3.2 upload_api.photo()

Android 端图片上传,将图片数据上传到 Instagram 上传服务器。

签名

upload_api.photo(image_data: bytes) -> UploadResult

参数

参数 类型 必填 说明
image_data bytes 图片的二进制数据,建议使用 JPEG 格式

返回值

返回 UploadResult 对象(详见第 4 节)。

异常

异常类型 触发条件
PermissionError 客户端未登录
RuntimeError 网络错误或上传失败

示例

import asyncio
import igapi

async def main():
    account = igapi.AccountInfo.parse("用户名:密码||设备信息|cookies||")
    client = igapi.Client(account=account)
    upload_api = igapi.UploadApi(client)

    with open("photo.jpg", "rb") as f:
        data = f.read()

    result = await upload_api.photo(data)
    print(result)
    # UploadResult(upload_id='...', status='ok', offset=...)

asyncio.run(main())

3.3 upload_api.configure()

将已上传的图片(Android 端上传)配置为帖子并发布。

签名

upload_api.configure(
    upload_id: str,
    caption: str | None = None,
    location_id: int | None = None,
    disable_comments: bool = False,
    hide_like_count: bool = False
) -> Media

参数

参数 类型 必填 默认值 说明
upload_id str photo() 返回的 upload_id
caption str \| None None 帖子文案,支持 emoji 和换行符 \n,最多 2200 字符
location_id int \| None None 位置标签 ID(可选,configure_web() 不支持此参数)
disable_comments bool False 是否禁用评论
hide_like_count bool False 是否隐藏点赞数

返回值

类型 说明
Media 发布成功的帖子信息

异常

异常类型 触发条件
PermissionError 客户端未登录
ValueError upload_id 无效或已过期
RuntimeError 发布失败或网络错误

3.4 upload_api.photo_web()

Web 端图片上传,仅限通过 WebClient 构造的 UploadApi 实例调用。

签名

upload_api.photo_web(image_data: bytes, width: int, height: int) -> UploadResult

参数

参数 类型 必填 说明
image_data bytes JPEG 格式图片的二进制数据
width int 图片宽度(像素),必须与实际尺寸匹配
height int 图片高度(像素),必须与实际尺寸匹配

返回值

返回 UploadResult 对象(字段与 photo() 相同)。

异常

异常类型 触发条件
TypeError 通过 Client(Android 平台)构造的 UploadApi 调用时抛出,错误信息:photo_web() requires WebClient
PermissionError 客户端未登录
RuntimeError 网络错误或上传失败

示例

import asyncio
import igapi

async def main():
    account = igapi.AccountInfo.parse("用户名:密码||设备信息|cookies||", platform="web")

    # 正确用法:通过 WebClient 构造
    web = igapi.WebClient(account=account)
    upload_api = igapi.UploadApi(web)
    result = await upload_api.photo_web(data, width=1080, height=1080)

    # 错误用法:通过 Client 构造(会抛出 TypeError)
    # client = igapi.Client(account=account)
    # upload_api = igapi.UploadApi(client)
    # result = await upload_api.photo_web(data, 1080, 1080)
    # TypeError: photo_web() requires WebClient

asyncio.run(main())

3.5 upload_api.configure_web()

将已上传的图片(Web 端上传)配置为帖子并发布,仅限通过 WebClient 构造的实例。

签名

upload_api.configure_web(
    upload_id: str,
    caption: str | None = None,
    disable_comments: bool = False,
    hide_like_count: bool = False
) -> Media

参数

参数 类型 必填 默认值 说明
upload_id str photo_web() 返回的 upload_id
caption str \| None None 帖子文案
disable_comments bool False 是否禁用评论
hide_like_count bool False 是否隐藏点赞数

返回值

类型 说明
Media 发布成功的帖子信息

异常

异常类型 触发条件
TypeError 通过 Client 构造的 UploadApi 调用时抛出,错误信息:configure_web() requires WebClient
PermissionError 客户端未登录
RuntimeError 发布失败或网络错误

4. 数据类型

4.1 UploadResult

上传操作的返回结果,包含后续 configure() 所需的 upload_id

字段 类型 说明
upload_id str 上传标识符,传给 configure()configure_web()
status str 上传状态,成功时为 "ok"
offset int 已上传字节偏移量(分片上传时使用)

示例

import asyncio
import igapi

async def main():
    account = igapi.AccountInfo.parse("用户名:密码||设备信息|cookies||")
    client = igapi.Client(account=account)
    upload_api = igapi.UploadApi(client)

    with open("photo.jpg", "rb") as f:
        data = f.read()

    result = await upload_api.photo(data)
    print(result)
    # UploadResult(upload_id='1234567890_123', status='ok', offset=204800)

    print(result.upload_id)   # '1234567890_123'
    print(result.status)      # 'ok'
    print(result.offset)      # 204800

asyncio.run(main())

4.2 UploadProgress

上传进度信息(供进度回调使用)。

字段 类型 说明
uploaded_bytes int 已上传字节数
total_bytes int 总字节数
stage str 当前阶段描述(中文,如 "上传中""已完成"
percentage float 完成比例,范围 0.01.0

方法

方法 返回值 说明
is_complete() bool stage == "已完成" 时返回 True

示例

print(progress)
# UploadProgress(stage='上传中', progress=45.3%)

print(f"进度: {progress.percentage * 100:.1f}%")
print(f"已完成: {progress.is_complete()}")

4.3 Media

发布成功的帖子信息。

字段 类型 说明
id str 帖子 ID
media_type int 媒体类型(1 = 图片,2 = 视频,8 = 轮播)
caption_text str 帖子文案文本
like_count int 点赞数
comment_count int 评论数

5. 上传流程图

Android 端上传流程

flowchart TD
    A([开始]) --> B[构造 UploadApi\nigapi.UploadApi\x28client\x29]
    B --> C[读取图片 bytes]
    C --> D[调用 photo\x28image_data\x29]
    D --> E{上传成功?}
    E -- 否 --> F([抛出 RuntimeError])
    E -- 是 --> G[获取 UploadResult\nupload_id / status / offset]
    G --> H[调用 configure\x28upload_id, ...\x29]
    H --> I{发布成功?}
    I -- 否 --> J([抛出 RuntimeError])
    I -- 是 --> K[返回 Media 对象]
    K --> L([结束])

Web 端上传流程

flowchart TD
    A([开始]) --> B[构造 UploadApi\nigapi.UploadApi\x28web\x29]
    B --> C[读取图片 bytes\n获取 width / height]
    C --> D[调用 photo_web\x28image_data, width, height\x29]
    D --> E{是 WebClient?}
    E -- 否 --> F([抛出 TypeError])
    E -- 是 --> G{上传成功?}
    G -- 否 --> H([抛出 RuntimeError])
    G -- 是 --> I[获取 UploadResult]
    I --> J[调用 configure_web\x28upload_id, ...\x29]
    J --> K{发布成功?}
    K -- 否 --> L([抛出 RuntimeError])
    K -- 是 --> M[返回 Media 对象]
    M --> N([结束])

6. 代码示例

6.1 Android 端完整上传发布流程

import asyncio
import igapi

async def main():
    account = igapi.AccountInfo.parse("用户名:密码||设备信息|cookies||")
    client = igapi.Client(account=account)
    upload_api = igapi.UploadApi(client)

    with open("landscape.jpg", "rb") as f:
        image_data = f.read()

    # 上传
    result = await upload_api.photo(image_data)
    print(f"上传完成,upload_id: {result.upload_id},状态: {result.status}")

    # 发布
    media = await upload_api.configure(
        upload_id=result.upload_id,
        caption="清晨的山谷,薄雾轻绕。\n\n#nature #landscape",
        disable_comments=False,
        hide_like_count=False
    )

    print(f"发帖成功!媒体 ID: {media.id},点赞数: {media.like_count}")

asyncio.run(main())

6.2 Web 端完整上传发布流程

import asyncio
import igapi

async def main():
    account = igapi.AccountInfo.parse("用户名:密码||设备信息|cookies||", platform="web")
    web = igapi.WebClient(account=account)
    upload_api = igapi.UploadApi(web)

    with open("portrait.jpg", "rb") as f:
        image_data = f.read()

    # Web 端上传(需要提供尺寸)
    result = await upload_api.photo_web(image_data, width=1080, height=1350)
    print(f"Web 上传成功,upload_id: {result.upload_id}")

    # Web 端发布
    media = await upload_api.configure_web(
        upload_id=result.upload_id,
        caption="人像摄影作品 #portrait #photography",
        hide_like_count=True
    )

    print(f"发帖成功!媒体 ID: {media.id}")

asyncio.run(main())

6.3 使用 Pillow 自动读取图片尺寸

Web 端上传需要提供准确的图片尺寸,推荐使用 Pillow 自动读取,避免手动填写错误:

import asyncio
import io
import igapi
from PIL import Image

async def main():
    account = igapi.AccountInfo.parse("用户名:密码||设备信息|cookies||", platform="web")
    web = igapi.WebClient(account=account)
    upload_api = igapi.UploadApi(web)

    img_path = "photo.jpg"
    with Image.open(img_path) as img:
        width, height = img.size
        # 确保是 JPEG 格式,PNG 需要转换
        if img.format != "JPEG":
            buf = io.BytesIO()
            img.convert("RGB").save(buf, format="JPEG", quality=95)
            image_data = buf.getvalue()
        else:
            with open(img_path, "rb") as f:
                image_data = f.read()

    result = await upload_api.photo_web(image_data, width=width, height=height)
    media = await upload_api.configure_web(result.upload_id, caption="自动读取尺寸上传")
    print(f"发帖成功:{media.id}")

asyncio.run(main())

6.4 错误处理示例

import asyncio
import igapi

async def main():
    account = igapi.AccountInfo.parse("用户名:密码||设备信息|cookies||")
    client = igapi.Client(account=account)
    upload_api = igapi.UploadApi(client)

    with open("photo.jpg", "rb") as f:
        image_data = f.read()

    try:
        result = await upload_api.photo(image_data)
        media = await upload_api.configure(result.upload_id, caption="测试帖子")
        print(f"发帖成功:{media.id}")
    except PermissionError:
        print("错误:未登录,请先完成登录")
    except ValueError as e:
        print(f"参数错误(upload_id 无效或已过期):{e}")
    except RuntimeError as e:
        print(f"运行时错误(网络或服务端问题):{e}")
    except TypeError as e:
        print(f"类型错误(photo_web/configure_web 使用了错误的客户端类型):{e}")

asyncio.run(main())

7. 平台差异

对比项 Android 端(photo() + configure() Web 端(photo_web() + configure_web()
可用客户端 ClientWebClient WebClient
上传时是否需要提供尺寸 不需要 必须提供 widthheight
上传协议 Android rupload 协议 Web rupload 协议
是否支持 location_id 支持(configure() 参数) 不支持
推荐使用场景 使用 Android 平台客户端,或需要位置标签 使用 WebClient 发帖

两种上传方式的 UploadResult 结构完全相同,均包含 upload_idstatusoffset 三个字段。


8. 注意事项

  1. photo_web()configure_web() 只能在 WebClient 上调用:通过 Client(Android 平台)构造的 UploadApi 调用这两个方法会抛出 TypeError

  2. 上传和配置必须配对:Android 端上传(photo())必须使用 configure() 发布;Web 端上传(photo_web())必须使用 configure_web() 发布。混用协议会导致发布失败。

  3. upload_id 有效期upload_id 在上传完成后有一定的有效期(通常几小时),超期需重新上传。

  4. 图片格式建议:建议使用 JPEG 格式,RGB 色彩空间,文件大小不超过 8 MB。Web 端对格式要求更为严格。

  5. Web 端尺寸必须准确photo_web() 要求 widthheight 与图片实际尺寸一致。填写错误的尺寸会导致帖子展示异常或发布失败。

  6. 简化发帖推荐使用 PostApi:如果使用 Web 平台且无需分步控制,直接使用 igapi.PostApi(web).create_photo() 更简洁,内部已封装上传和配置两步。


9. 常见问题

Q:photo_web() 抛出 TypeError: photo_web() requires WebClient,怎么解决?

原因是通过 Client(Android 平台)构造了 UploadApi,而非 WebClient。请确认使用正确的客户端:

# 错误
client = igapi.Client(account=account)
upload_api = igapi.UploadApi(client)
upload_api.photo_web(data, 1080, 1080)  # TypeError!

# 正确
web = igapi.WebClient(account=account)
upload_api = igapi.UploadApi(web)
upload_api.photo_web(data, 1080, 1080)  # 正常

Q:Web 端上传时不知道图片尺寸怎么办?

使用 Pillow 库读取图片尺寸(参考第 6.3 节示例)。传入错误的尺寸值会导致帖子展示异常或发布失败,建议始终从实际图片数据中读取尺寸,不要手动估算。


Q:UploadApiPostApi.create_photo() 应该用哪个?

场景 推荐方案
Web 平台发布单张图片,无特殊需求 PostApi.create_photo(),更简洁
Android 平台客户端发帖 UploadApi.photo() + configure()
需要添加位置标签(location_id UploadApi.configure()
需要在上传和发布之间插入自定义逻辑 UploadApi,分步控制

Q:configure() 中的 location_id 如何获取?

location_id 是 Instagram 地点的数字 ID,可以通过 Instagram 地点搜索接口获取。当前版本暂未提供直接的位置搜索 API,可通过 Web 端 GraphQL 或第三方工具查询特定地点的 ID 后传入。