在星座社区与社交 App 里接入星座运势查询:数据表、刷新时序与分享图

约 14 分钟 进阶星座社区社交App集成场景数据表设计
# 在星座社区与社交 App 里接入星座运势查询:数据表、刷新时序与分享图 接口 872(两接入点)· 免费服务 · POST / GET · 返回 JSON · 适用:产品经理、社区与社交产品全栈 · 阅读时间:约 8 分钟 · 最后实测核对:2026-09-18 ## 核心要点 - 星座运势查询接口(apiCode=872)提供多周期运势与生日识别,星座配对接口提供双人互动,两个接入点配合就能覆盖社区产品的日常内容供给。 - 数据每天 1 点、7 点、17 点更新,落库加缓存的组合能把用户请求全部挡在本地,回源只剩定时任务。 - 配对结果是娱乐性质,接口文档标注「数据结果仅供娱乐参考」,结果页与分享图保留这句说明。 ## 一个星座社区需要哪些数据 社区产品的星座板块通常有三类页面:今日运势卡片、配对互动页、周月趋势页。 第一类每天开一次,用户看的是综合指数、吉色、幸运数字和一段简评。第二类是社交入口,两人各填星座说一句「配不配」。第三类面向愿意停留更久的用户,看的是本周提醒与本月优势弱势。 这三类页面用到的数据都来自同一个接口的两个接入点。接入点 1 提供多周期运势,接入点 2 提供配对结果。 ## 能力盘点 | 能力 | 接入点 | 常用场景 | |---|---|---| | 多周期运势 | 872-1 | 今日签、周趋势、月总览 | | 生日识别星座 | 872-1 的 `date` 参数 | 用户填生日即出运势,少一个下拉控件 | | 星座配对 | 872-2 | 配对测试、破冰互动、分享图 | | 免费与定时更新 | 两个接入点 | 低成本的内容底座 | ## 数据表设计 落库的目标是让用户请求不打到接口上。两张表配合一层缓存就够用。 ```sql -- 运势:一个星座一个周期一天一行 CREATE TABLE horoscope_cache ( star VARCHAR(16) NOT NULL, -- baiyang / jinniu ... period VARCHAR(12) NOT NULL, -- day / tomorrow / week / month / year bucket VARCHAR(16) NOT NULL, -- 20260918 / 202609 / 2026 / week:20260913 payload JSON NOT NULL, fetched_at DATETIME NOT NULL, PRIMARY KEY (star, period, bucket) ); -- 配对:两个星座一组,顺序无关 CREATE TABLE match_cache ( star_a VARCHAR(16) NOT NULL, -- 排序后的较小值 star_b VARCHAR(16) NOT NULL, -- 排序后的较大值 payload JSON NOT NULL, fetched_at DATETIME NOT NULL, PRIMARY KEY (star_a, star_b) ); ``` `bucket` 按周期各自的粒度取值。实测 `day` 的 `time` 是 `20260918`、`week` 是 `20260913-20260920`、`month` 是 `202609`、`year` 是 `2026`,落库时按对应粒度切分,避免周月年的数据跟着每天刷新。 配对表的两个星座列建议写入前排序。2026-09-18 实测 `tianxie` 配 `shuiping` 与 `shuiping` 配 `tianxie` 的 `match` 都是 `50分`、`proportion` 都是 `58:42`,性别也不影响结果,键收敛后缓存命中率更高。 ## 刷新时序 ``` 01:05 / 07:05 / 17:05 定时任务触发 → 12 个星座各取一次全周期运势(带齐 needX 开关) → 按周期拆分写入 horoscope_cache → 同步刷新 Redis,TTL 对齐下一个更新窗口 用户请求 → 先读 Redis → 未命中读 horoscope_cache → 仍未命中才回源,并写入两层 ``` 一轮预热是 12 次调用,对比基础版每日 100 次的额度留有余量。预热任务本身建议加令牌桶,把并发控制在档位允许的 QPS 内。 ## 代码 Python(取数并落库): ```python import json import requests STARS = ["baiyang", "jinniu", "shuangzi", "juxie", "shizi", "chunv", "tiancheng", "tianxie", "sheshou", "mojie", "shuiping", "shuangyu"] BASE = "https://route.showapi.com" def fetch_one_star(star: str, appkey: str) -> dict: """取一个星座的五个周期,返回 {period: payload}。""" data = requests.get(f"{BASE}/872-1", params={ "appKey": appkey, "star": star, "needTomorrow": "1", "needWeek": "1", "needMonth": "1", "needYear": "1", }, timeout=15).json() if data.get("showapi_res_code") != 0: raise RuntimeError(f"系统错误: {data.get('showapi_res_error')}") body = data["showapi_res_body"] if str(body.get("ret_code")) != "0": raise RuntimeError(f"业务错误: {body.get('remark')}") return {p: body[p] for p in ("day", "tomorrow", "week", "month", "year") if body.get(p)} def fetch_match(star_a: str, star_b: str, appkey: str) -> dict: """配对取数;两个星座先排序,与顺序无关。""" a, b = sorted([star_a, star_b]) data = requests.get(f"{BASE}/872-2", params={ "appKey": appkey, "star1": a, "gender1": "1", "star2": b, "gender2": "0", }, timeout=5).json() if data.get("showapi_res_code") != 0: raise RuntimeError(f"系统错误: {data.get('showapi_res_error')}") body = data["showapi_res_body"] if str(body.get("ret_code")) != "0": raise RuntimeError(f"业务错误: {body.get('remark')}") return body if __name__ == "__main__": for star in STARS: periods = fetch_one_star(star, "YOUR_APPKEY") print(star, {p: periods[p]["time"] for p in periods}) ``` cURL 与 Node.js: ```bash curl -G "https://route.showapi.com/872-2" \ --data-urlencode "appKey=YOUR_APPKEY" \ --data-urlencode "star1=jinniu" \ --data-urlencode "gender1=1" \ --data-urlencode "star2=baiyang" \ --data-urlencode "gender2=0" \ --max-time 5 ``` ```javascript // 配对结果先排序再查,与用户填写顺序无关 const [a, b] = ["shuiping", "tianxie"].sort(); const url = new URL("https://route.showapi.com/872-2"); Object.entries({ appKey: "YOUR_APPKEY", star1: a, gender1: "1", star2: b, gender2: "0" }) .forEach(([k, v]) => url.searchParams.set(k, v)); const data = await (await fetch(url, { signal: AbortSignal.timeout(5000) })).json(); if (String(data.showapi_res_body?.ret_code) !== "0") throw new Error("业务失败"); console.log(data.showapi_res_body.match, data.showapi_res_body.proportion); ``` ## 前端展示 今日签卡片取 `day` 的 `summary_star`、`lucky_color`、`lucky_num`、`general_txt` 四项就够。`summary_star` 是数字,直接映射星级;`lucky_color` 返回的是中文颜色名(实测出现过 `金色`、`天蓝`、`海蓝色`),需要一层色值映射表。 配对页取 `match` 做大字,`proportion` 做双方比重条,`review` 做标题。`match` 是带「分」字的字符串,渲染前去掉单位。 分享图的配色可以直接跟随 `lucky_color`,不必在代码里写死色板。 ## 用户身份与配对结果的对应 返回体里的 `star1`、`star2` 与 `gender1`、`gender2` 不保证按同一位置对应。2026-09-18 实测传入 `star1=baiyang`(`gender1=0`)、`star2=jinniu`(`gender2=1`)时,返回 `star1=jinniu`、`star2=baiyang`,而 `gender1` 仍是「女」。 落库与渲染时按两组字段分别取:星座看 `grxz1` / `grxz2`,性别看 `gender1` / `gender2`,不要按位置拼成同一个人的档案。 配对结果为娱乐性质,接口文档明确标注「数据结果仅供娱乐参考」。结果页、分享图与推送文案都保留这句说明。 ## 生日信息的处理 `date` 参数只吃四位 `MMdd`,接口文档也没有要求年份。前端收集生日时只取月和日,用户信息里少存一项,映射区间以接口返回的 `star` 为准。 接口实际使用的星座边界与常见对照表有差异,接口自己判出来的边界见 date 参数那篇的实测表。 ## FAQ **Q1:每天需要调多少次接口?** 预热一轮是 12 个星座各一次,共 12 次调用。用户请求全部走缓存,不额外消耗额度。 **Q2:配对能做成付费功能吗?** 可以,付费点建议放在更长的解读文案、历史对比或去广告上。结果页保留「仅供娱乐参考」的说明。 **Q3:多周期要一次取还是分开取?** 一次带齐四个 `needX` 开关取,比调五次省调用次数。取回后按周期拆开写缓存。 **Q4:用户填的生日要不要存年份?** 不需要。接口只接受 `MMdd`,不收年份也就少一项需要保管的用户信息。 **Q5:接口不可用时页面怎么处理?** 展示兜底文案并保留上一次的缓存数据,不要白屏。缓存策略那篇有 TTL 与预热的具体写法。 **Q6:星座和性别的字段能拼成同一个人的展示元素吗?** 不能。实测返回的 `star1` / `star2` 顺序与 `gender1` / `gender2` 的位置不保证对应,两组字段分别取值。 ## 下一步阅读 - [星座运势查询的缓存怎么设](https://www.showapi.com/guides/horoscope-cache-872) - [星座类产品的三条内容线](https://www.showapi.com/guides/horoscope-product-plan-872) - [星座运势查询的 date 参数:按生日识别星座](https://www.showapi.com/guides/horoscope-by-date-872) - [星座配对:用四个必填参数算出配对指数](https://www.showapi.com/guides/constellation-match-quickstart-872) - **本系列共 13 篇**:查看[星座运势 API 指南总目录](https://www.showapi.com/guides/horoscope-guides-872)
加载中...