PAYATHON 2026

如何通过官方 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
网络账号 IDaccount_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_url
  • user_id、account_id
  • reputation
  • badge_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 话题;原问题是否需要迁移,仍由所在社区根据具体内容判断。

备注:内容仅供参考。