- 后端
【免费下载链接】instagram-private-api
NodeJS Instagram private API SDK. Written in TypeScript.
导读
TagFeedResponseStoryLocationsItem是 instagram-private-api(NodeJS Instagram 私有 API SDK)中用于描述标签话题页(hashtag)Story Tray 内"位置贴纸(location sticker)"的响应数据模型。在 TypeScript 中它被定义为TagFeedResponse的嵌套接口,承载每个位置贴纸在故事画布上的坐标、尺寸、旋转角与层级信息,并内嵌一个TagFeedResponseLocation地点对象。读完本文,你将掌握该接口全部字段的含义与数据类型、它在TagFeed标签故事流中的实际 JSON 形态,以及如何通过StickerBuilder在发布端构造与之对称的位置贴纸数据,实现"读取标签页故事 → 解析地点贴纸 → 结构化使用地点信息"的完整链路。
一、接口定位:标签页 Story Tray 的贴纸清单
TagFeedResponseStoryLocationsItem不是孤立的数据类型,它隶属于标签话题 Feed 的整体响应结构。在 tag.feed.response.ts 中,TagFeedResponse顶层接口定义了标签页响应的骨架:
export interface TagFeedResponse { ranked_items: TagFeedResponseRankedItemsItem[]; items: TagFeedResponseItemsItem[]; num_results: number; next_max_id: string; more_available: boolean; auto_load_more_enabled: boolean; story: TagFeedResponseStory; status: string; }其中story: TagFeedResponseStory是标签页顶部的 Story Tray(若干账号的最新快拍合集),其items: TagFeedResponseItemsItem[]中的每一个快拍条目(TagFeedResponseItemsItem)都可能携带一组贴纸数据,其中就包括位置贴纸:
export interface TagFeedResponseItemsItem { // ... 媒体基础字段(pk、media_type、image_versions2 等) is_reel_media?: boolean; expiring_at?: number; story_hashtags?: TagFeedResponseStoryHashtagsItem[]; creative_config?: TagFeedResponseCreative_config; reel_mentions?: TagFeedResponseReelMentionsItem[]; story_locations?: TagFeedResponseStoryLocationsItem[]; // ← 本文主角 // ... }也就是说,一个快拍条目下通常会有"话题贴纸数组(story_hashtags)、@提及贴纸数组(reel_mentions)、位置贴纸数组(story_locations)"三类贴纸清单,TagFeedResponseStoryLocationsItem就是其中位置贴纸清单的单个元素类型,最终由 tag.feed.response.ts#L274-L284 定义。
数据来源链路
该响应来自TagFeed对 Instagram 私有接口/api/v1/feed/tag/{tag}/的请求。在 tag.feed.ts 中可以看到请求参数包含rank_token(由基类Feed用Chance生成的 GUID,见 core/feed.ts)和分页游标max_id:
async request() { const { body } = await this.client.request.send<TagFeedResponse>({ url: `/api/v1/feed/tag/${encodeURI(this.tag)}/`, qs: { rank_token: this.rankToken, max_id: this.nextMaxId, }, }); this.state = body; return body; }TagFeed.state会把more_available与next_max_id写入内部状态,用于items$可观测流的持续翻页拉取(参见 core/feed.ts 的 retry/分页逻辑),因此标签页的快拍及其贴纸可以通过分页接口全部枚举出来。
二、接口全景:字段速览
对照 TagFeedResponseStoryLocationsItem.md 文档,该接口共 9 个属性,逐一对应源码 tag.feed.response.ts#L274-L284:
| 属性 | 类型 | 语义 |
|---|---|---|
x | number \| string | 贴纸中心点水平坐标(归一化) |
y | number \| string | 贴纸中心点垂直坐标(归一化) |
z | number | 图层层级(z 序) |
width | number \| string | 贴纸宽度(占画布比例) |
height | number \| string | 贴纸高度(占画布比例) |
rotation | number | 旋转角度(度) |
is_pinned | number | 是否被固定(1/0 布尔量的数值形式) |
is_hidden | number | 是否被隐藏(1/0 布尔量的数值形式) |
location | TagFeedResponseLocation | 内嵌的地点对象(名称、地址、经纬度、POI ID 等) |
三、字段详解:从坐标到地点对象
3.1 几何定位字段:x、y、z
x: number | string— 贴纸在画布上的水平位置。在 instagram-private-api 的贴纸体系中,坐标采用归一化坐标系:x、y的取值范围为 0~1,0.5代表画布正中央。这一点可以从发布端基类InstaSticker的默认值与定位方法得到印证(见 insta-sticker.ts):public x: number = 0.0; public y: number = 0.0; public center(): this { this.x = 0.5; this.y = 0.5; return this; }响应字段同时声明为
number | string,从类型设计上可以推断:Instagram 服务端在不同场景下可能返回数字或字符串形式的坐标,SDK 因此用联合类型保持对两种序列化形态的兼容。z: number— 图层 z 序。数字越大越靠前显示。发布端InstaSticker.moveForward(layers)/moveBackwards(layers)正是通过增减z值来调整贴纸前后遮挡关系(insta-sticker.ts)。
3.2 尺寸与旋转:width、height、rotation
width/height: number | string— 贴纸占故事画布的宽高比例(归一化),同样存在number | string联合类型。发布端默认值可参考:LocationSticker的默认宽高为width = 0.47、height = 0.111(见 location.sticker.ts),即位置贴纸默认横向占据画布的约 47% 宽、11% 高。rotation: number— 贴纸旋转角度,单位是度(degree)。发布端rotateDeg(deg)方法会执行deg % 360.0归一化(insta-sticker.ts),因此响应中的取值通常落在 0~360 区间。
3.3 显示状态:is_pinned、is_hidden
is_pinned: number— 贴纸是否被"钉住"。在类型定义中它是number而非boolean,实际取值遵循 Instagram 序列化约定:1表示是,0表示否。is_hidden: number— 贴纸是否处于隐藏状态(例如用户在发布后手动隐藏了该贴纸),同样是1/0数值。
3.4 核心业务字段:location: TagFeedResponseLocation
location是整个贴纸条目的"灵魂"——它承载了该贴纸对应的真实地点信息。其定义位于 tag.feed.response.ts#L84-L94:
export interface TagFeedResponseLocation { pk: number | string; // 地点的唯一主键(IG location id) name: string; // 地点显示名称 address: string; // 详细地址 city: string; // 城市 short_name: string; // 短名称(如品牌名、街区简称) lng: number | string; // 经度 lat: number | string; // 纬度 external_source: string; // 外部数据源标识(如 facebook_places) facebook_places_id: string | number; // Facebook Places 的地点 ID }各字段用途:
pk可用来在后续请求中定位该地点(例如结合locationSearch反查地点详情);name/address/city/short_name是可直接展示给终端用户的地点文本信息;lat/lng提供了贴纸地点的精确经纬度,可用于地图渲染、距离计算或 POI 聚合;external_source与facebook_places_id说明了该 POI 的底层数据来源(通常是 Facebook Places 数据库),这在做地点去重、关联商业 POI 时非常关键。
四、发布与读取的对称关系:StickerBuilder 如何生成同构数据
TagFeedResponseStoryLocationsItem描述的是"读取侧"(服务端响应)的位置贴纸形态;而在"发布侧",instagram-private-api 用StickerBuilder.location()构造完全同构的数据,二者在字段语义上一一对应。
4.1 发布侧:LocationSticker与StoryLocation
发布位置贴纸需要两层对象:
贴纸几何对象
StoryLocation,继承StorySticker基类(media.configure-story.options.ts#L71-L77),拥有x、y、width、height、rotation等几何字段,并附加is_sticker: boolean与location_id: string:export interface StorySticker { x: number; y: number; width: number; height: number; rotation: number; } export interface StoryLocation extends StorySticker { is_sticker: boolean; location_id: string; }可以看到,发布侧的
location_id正是读取侧TagFeedResponseLocation.pk的输入来源——贴纸的地点身份在两端是同一 ID。贴纸构造器
LocationSticker(location.sticker.ts),它确定了贴纸的唯一标识与序列化键名:export class LocationSticker extends InstaSticker { public locationId: string; width = 0.47; height = 0.111; get id(): string { return 'location_sticker_vibrant'; } get key(): string { return 'story_locations'; // ← 与响应字段 story_locations 同名 } }
StickerBuilder.location()(sticker-builder.ts#L82-L84)负责把普通配置对象转换成LocationSticker实例,而StickerBuilder.build()(sticker-builder.ts#L30-L52)会把贴纸按key分组、JSON 序列化,并聚合出story_sticker_ids——这正是configureToStory需要的story_locations表单载荷。
4.2 配置项约束:geotag_enabled与坐标联动
在 media.configure-story.options.ts 中有两条明确的注释约束:
// if this is set, the geotag has to be set! story_locations?: [StoryLocation] | string; geotag_enabled?: '1' | '0'; posting_latitude?: string; posting_longitude?: string; media_latitude?: string; media_longitude?: string;设置story_locations时,必须同时开启geotag_enabled = '1'并携带经纬度四项参数,否则服务端会拒绝配置。这一点在发布服务中有完整的实现印证——publish.service.ts#L337-L347:
if (typeof options.location !== 'undefined') { const { latitude, longitude } = options.location; configureOptions.geotag_enabled = '1'; configureOptions.posting_latitude = latitude; configureOptions.posting_longitude = longitude; configureOptions.media_latitude = latitude; configureOptions.media_longitude = longitude; configureOptions.story_locations = [options.location.sticker]; configureOptions.mas_opt_in = 'NOT_PROMPTED'; }其中options.location的类型为PostingStoryLocationSticker(posting.options.ts#L52-L55),由latitude、longitude与sticker: StoryLocation三部分组成。
4.3 序列化:stringifyStoryStickers
在最终提交configureToStory前,media.repository.ts#L401-L419 的stringifyStoryStickers会对非字符串数组的贴纸数据做JSON.stringify:
const serialize = (obj: any | undefined) => { if (typeof obj !== 'undefined' && Array.isArray(obj) && obj.length > 0 && typeof obj[0] !== 'string') { return JSON.stringify(obj); } return obj; }; form.story_hashtags = serialize(form.story_hashtags); form.story_locations = serialize(form.story_locations); // ... 其余贴纸字段同理这说明服务端收到的story_locations是 JSON 字符串,而TagFeedResponse返回的story_locations则是反序列化后的对象数组——两端通过同一字段名story_locations完成了数据的闭环。
五、实战:读取标签页故事中的位置贴纸
综合以上链路,读取一个标签页 Story Tray 中所有位置贴纸的完整示例:
import { IgApiClient } from '../src'; import { TagFeed } from '../src/feeds'; const ig = new IgApiClient(); ig.state.generateDevice(process.env.IG_USERNAME); await ig.account.login(process.env.IG_USERNAME, process.env.IG_PASSWORD); const tagFeed: TagFeed = ig.feed.tag('foodie'); // 话题标签 const story = await tagFeed.request(); // TagFeedResponse // story.items 是该标签页 Story Tray 的快拍列表 for (const item of story.items) { // 位置贴纸是可选项:item.story_locations?: TagFeedResponseStoryLocationsItem[] if (!item.story_locations || item.story_locations.length === 0) { continue; } for (const sticker of item.story_locations) { const { location } = sticker; console.log({ mediaId: item.id, stickerGeometry: { x: sticker.x, y: sticker.y, z: sticker.z, width: sticker.width, height: sticker.height, rotation: sticker.rotation, pinned: sticker.is_pinned, hidden: sticker.is_hidden, }, place: { pk: location.pk, name: location.name, address: location.address, city: location.city, shortName: location.short_name, coordinates: { lat: location.lat, lng: location.lng }, externalSource: location.external_source, facebookPlacesId: location.facebook_places_id, }, }); } }5.1 结合locationSearch反查地点
发布侧示例 upload-story.example.ts 展示了如何通过地点搜索接口获取真实地点 ID 来构造贴纸:
.add( StickerBuilder.location({ locationId: (await ig.locationSearch.index(13, 37)).venues[0].external_id, }), )locationSearch.index(lat, lng)返回候选地点列表,取external_id作为locationId。该external_id与读取侧TagFeedResponseLocation.pk/facebook_places_id体系同源,可以在"搜索地点 → 发布位置贴纸 → 读取他人故事中的地点贴纸"之间建立一致的地点主键映射。
六、边界情况与注意事项
- 字段可选性:
story_locations在TagFeedResponseItemsItem中定义为可选属性(story_locations?: TagFeedResponseStoryLocationsItem[],见 tag.feed.response.ts#L185)。并非每个标签快拍都带有位置贴纸,访问前务必做空值判断,或使用?.与?? []防御式取值。 - 数值联合类型:
x、y、width、height是number | string,location.pk、lat、lng、facebook_places_id同理。做坐标运算或数值比较时,建议先Number()转换,避免字符串拼接导致结果异常。 - 数值型布尔量:
is_pinned、is_hidden是number而非boolean,判断时用=== 1/=== 0,而不是直接当成 truthy 布尔值(0在 JS 中是 falsy,但2等意外值也可能出现)。 is_reel_media前置条件:story_locations只出现在快拍类条目上(is_reel_media: true的条目),普通时间线帖子(items/ranked_items中的非快拍媒体)不会携带该字段。- Direct Story 不支持贴纸:在发布侧,publish.service.ts#L302-L315 明确注释 "directThread => no stickers supported"——当
threadIds/recipientUsers存在时configure_mode = '2'且贴纸配置被忽略。这与读取侧逻辑一致:只有发布到 Story Tray(configure_mode = '1')的内容才会在TagFeed响应中出现贴纸数据。 - 同构接口族:
TagFeedResponseStoryLocationsItem并非唯一的位置贴纸模型。在 user-story.feed.response.ts、list-reel-media-viewer.feed.response.ts、reels-tray.feed.response.ts、location.repository.story.response.ts 等响应文件中也存在结构相近的StoryLocationsItem类型,但各自绑定不同的响应上下文(用户主页故事、快拍查看者列表、Reels Tray、地点故事)。如需通用处理,可依据本接口的几何 +location双段结构设计统一的解析器。
七、小结
TagFeedResponseStoryLocationsItem是 instagram-private-api 中"标签页故事流位置贴纸"的标准数据契约:
- 读取侧:通过
TagFeed请求/api/v1/feed/tag/{tag}/,在story.items[].story_locations[]中取得贴纸的归一化几何信息(x/y/z/width/height/rotation)、显示状态(is_pinned/is_hidden)与完整地点对象(TagFeedResponseLocation); - 发布侧:通过
StickerBuilder.location({ locationId })+ig.publish.story({ location })构造同构数据,需满足geotag_enabled='1'与经纬度四参数联动的约束; - 闭环价值:两端的
location_id与location.pk同源,使得"地点搜索 → 贴纸发布 → 标签故事采集 → 地点聚合分析"可以在同一个 SDK 内完成,适用于地点打卡统计、POI 热度分析、地图聚合展示等场景。
如需深入阅读接口文档与源码,可参考:
- 接口文档:TagFeedResponseStoryLocationsItem.md(含各字段 Defined in 行号)
- 内嵌地点对象:TagFeedResponseLocation.md
- 源码定义:tag.feed.response.ts
- 标签 Feed 请求:tag.feed.ts
- 发布实现:publish.service.ts、media.repository.ts
- 贴纸构造器:sticker-builder.ts、location.sticker.ts、insta-sticker.ts
- 配置类型:media.configure-story.options.ts
- 完整示例:upload-story.example.ts
- 后端
【免费下载链接】instagram-private-api
NodeJS Instagram private API SDK. Written in TypeScript.
相关推荐
OWASP CheatSheetSeries 之 CI/CD 安全速查表:从流水线加固到供应链防护的完整实践指南
OWASP CheatSheetSeries 之 CI/CD 安全速查表:从流水线加固到供应链防护的完整实践指南 CI/CD 流水线已成为现代软件交付的核心基础
后端instagram-private-api 响应接口 LocationRepositoryStoryResponseReelMentionsItem 全解析:位置 Story 中 @提及贴纸的数据结构
instagram private api 响应接口 LocationRepositoryStoryResponseReelMentionsItem 全解析:位
后端instagram-private-api 中 ReelsMediaFeedResponseStoryPollsItem 接口详解:解析 Reels/Story 投票贴纸的响应结构
instagram private api 中 ReelsMediaFeedResponseStoryPollsItem 接口详解:解析 Reels/Story
后端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考