如何通过官方 API 获取 Stack Exchange 各站点的个人统计数据?
可以通过 Stack Exchange 官方 HTTP API 获取声望和金、银、铜徽章数量,无需抓取网页。API 返回 JSON,既可以用 JavaScript 调用,也可以在 ASP.NET 中用 C# 的 HttpClient 调用。官方文档见 Stack Exchange API。
如果 flair 包含多个站点,建议先获取并缓存关联账号的统计数据,鼠标悬停时直接读取缓存。
获取指定站点的用户统计
查询单个站点的用户资料,使用:
GET https://api.stackexchange.com/2.3/users/{user_id}?site={site}
参数说明:
user_id是用户在该站点的 ID,通常可以从个人资料页的/users/数字/…中找到。site指定站点,可以使用完整域名,例如stackoverflow.com、puzzling.stackexchange.com、math.stackexchange.com。
同一个人在不同站点的 user_id 可能不同,必须与 site 配套使用。参数说明见 /users/{ids} 文档,站点参数规则见 API 总览。
响应中的用户对象位于 items 数组,界面所需数据对应以下字段:
| 界面内容 | API 字段 |
|---|---|
| 声望 | reputation |
| 金徽章数量 | badge_counts.gold |
| 银徽章数量 | badge_counts.silver |
| 铜徽章数量 | badge_counts.bronze |
| 用户显示名称 | display_name |
| 网络账号 ID | account_id |
reputation 返回整数,6.2k 这样的缩写需要由前端格式化。完整字段说明见 user 类型文档。
获取多个关联站点的统计
要展示自己在多个 Stack Exchange 站点的数据,可以先从任意一个站点的用户对象中取得 account_id,再调用:
GET https://api.stackexchange.com/2.3/users/{account_id}/associated?page=1&pagesize=100
/users/{ids}/associated 接收的是网络账号的 account_id,单站点 /users/{ids} 接收的则是该站点的 user_id。两者需要区分,具体说明见 /users/{ids}/associated 文档。
该接口返回关联站点的账号对象,包括:
site_name、site_urluser_id、account_idreputationbadge_counts
如果只需要显示声望和徽章数量,直接使用这些结果即可,不必逐个站点查询用户资料。字段定义见 network_user 文档。
如果响应中的 has_more 为 true,需要继续请求下一页,直到为 false,才能获取全部关联账号。具体规则见 分页文档。
建议用 site_url 的域名匹配站点图标,避免依赖返回顺序或显示名称。
JavaScript 调用示例
将下面的单站点查询函数放到现有页面的脚本中,在页面初始化时调用。传入的 ID 必须属于指定站点。
async function fetchUserStats(site, userId) {
const url = new URL(
`https://api.stackexchange.com/2.3/users/${encodeURIComponent(userId)}`
);
url.searchParams.set("site", site);
const response = await fetch(url);
const data = await response.json();
if (!response.ok || data.error_id !== undefined) {
throw new Error(data.error_message || `HTTP ${response.status}`);
}
const user = data.items?.[0];
if (!user) {
throw new Error("未找到用户,请检查 site 和 user_id。");
}
return {
user,
backoff: data.backoff,
quotaRemaining: data.quota_remaining
};
}
function showUserStats(siteName, user) {
document.getElementById("site-name").textContent = siteName;
document.getElementById("rep").textContent = user.reputation;
document.getElementById("gold").textContent = user.badge_counts.gold;
document.getElementById("silver").textContent = user.badge_counts.silver;
document.getElementById("bronze").textContent = user.badge_counts.bronze;
}
调用时,将占位 ID 12345 替换为实际的用户 ID:
fetchUserStats("stackoverflow.com", 12345)
.then(({ user, backoff, quotaRemaining }) => {
showUserStats("Stack Overflow", user);
// 请求调度器应记录 backoff,限制后续对同一方法的请求。
console.log({ backoff, quotaRemaining });
})
.catch(error => {
console.error("加载统计数据失败:", error);
});
用户对象的字段结构见 user 文档。backoff 和 quota_remaining 属于响应外层的公共包装对象。
要接入原来的悬停交互,可以按站点域名保存查询结果:
const statsBySite = new Map();
// 获取数据后保存:
// statsBySite.set("stackoverflow.com", user);
// 鼠标悬停时读取:
function showSiteStats(site, siteName) {
const user = statsBySite.get(site);
if (user) {
showUserStats(siteName, user);
}
}
鼠标经过图标时只更新 DOM,不会发起新的 API 请求。多个站点的数据可以通过前面的 /associated 接口统一获取并填入缓存。
在 ASP.NET 中部署时需要注意什么
在 ASP.NET 中,用 HttpClient 请求相同的 URL 并解析 JSON 即可,不需要专用的 C# SDK。服务端应复用 HttpClient,并配置响应自动解压,因为官方 API 使用 GZIP 或 DEFLATE 压缩响应。压缩细节见官方说明。
如果每月刷新两次,可以让 ASP.NET 后台定时更新一份统计快照,再通过自己的接口或页面数据交给 JavaScript。刷新失败时保留上一份成功结果,同时显示上次更新时间。
部署时还需要注意:
- 官方 API 大量使用缓存,数据不保证实时。官方要求避免在一分钟内重复发送语义相同的请求;每月刷新两次可以作为应用自己的更新策略。见限流文档。
- 响应出现
backoff时,必须等待指定秒数后才能再次调用同一 API 方法,包括请求下一页。同时需要关注quota_remaining。 - 读取这些公开统计数据不需要用户 OAuth 授权,可以先匿名调用。需要更高配额时,可注册应用并使用 API key。API key 与用户 OAuth access token 的用途不同,具体见 API 总览和身份验证帮助。
- 如果默认的“Stack Exchange”一行显示各站点之和,应用需要明确选择参与汇总的站点并计算。自行求和的结果不能直接视为官方 flair 的汇总值。
API 问题应该去哪里提问
官方 API 文档将 Stack Apps列为 API 疑问、错误报告和应用展示的交流场所。API 使用问题可以优先在那里查找或提问。有关 Stack Overflow 提问规则、迁移规则的讨论属于 Meta 话题;原问题是否需要迁移,仍由所在社区根据具体内容判断。
备注:内容仅供参考。
