做一个真能查出谁取关了你的推特粉丝追踪器

20 min readSocialAPI 工程团队

做一个真能查出谁取关了你的推特粉丝追踪器

你的粉丝数从 4,102 变成了 4,098。

四个人走了。X 不会告诉你是谁,也不会告诉你什么时候。到明天,三个新粉丝进来,数字又变回 4,101 —— 像什么都没发生过。

这个缺口就是粉丝追踪工具存在的理由。而大多数工具处理得并不好。

这篇讲怎么做一个真正管用的,以及那个决定它到底能不能查出东西的设计选择。


为什么光看数字没用

任何 X 主页都有 followers_count,一个实时更新的数字。它把你真正想知道的东西全藏起来了。

设想某一天你涨了 12 个粉、掉了 12 个粉。数字纹丝不动。在任何基于计数的追踪器看来,这一天什么也没发生 —— 而实际上有 24 个关系变了,走掉的那 12 个可能恰恰是最重要的。

数字给你的是净值,追踪需要的是集合。

把这个集合从 X 里完整拿出来才是费劲的部分 —— 我们把它做成了一次调用,你可以直接从差集逻辑开始写。

这一个区别,就是"能用的追踪器"和"在你的受众底下暗流涌动时报一条平线"的分水岭。


真正重要的那个设计选择

想知道谁取关了,你得比对两份粉丝列表快照 —— 昨天的和今天的。剩下的交给集合运算:

新增粉丝 = 今天 − 昨天
取关的人 = 昨天 − 今天

很简单。人们做错的地方在于:每份快照里到底存什么。

直觉是把整个资料都存下来 —— 昵称、简介、头像、粉丝数,全套。看起来周全,但这正是大多数自建追踪器一个月内就变慢变贵的原因。

检测变化不需要资料,只需要身份。 存 ID;只对真正发生变化的那几个账号去查资料。

对一个 5 万粉的账号,这是"每天存 5 万份完整资料"和"每天存 5 万个整数"的区别。而在抓取那一侧,轻量接口的单次成本也低于完整版 —— 这个差价每天都在累加。


可运行的代码

两步:拉当前粉丝集合,和上次的结果做差集。

第一步 —— 拉粉丝列表

import requests

BASE = "https://api.socialapi.tech"
KEY  = "your_api_key"

def get_followers(username):
    """返回完整的粉丝 ID 集合, 一直翻页到底。"""
    ids, cursor = set(), None

    while True:
        params = {"username": username, "limit": 200}
        if cursor:
            params["cursor"] = cursor

        r = requests.get(
            f"{BASE}/v1/user/followers_ids",
            params=params,
            headers={"X-API-Key": KEY},
            timeout=60,
        )
        r.raise_for_status()
        body = r.json()

        for row in body["data"]:
            ids.add(row["id"])

        cursor = body.get("meta", {}).get("next_cursor")
        if not cursor:
            break

    return ids

注意用的是 followers_ids 而不是 followers —— 它只返回 {id, username},而差集需要的就只有这些。

翻页上最坑人的一个细节: 结束条件是 next_cursor 为空,不是某一页返回的条数少于你要的数量。列表中间出现短页是正常的,不代表到底了。如果把短页当成终点,你会悄无声息地截断列表 —— 而这在下一次运行时会表现为一大批根本不存在的"取关"。

第二步 —— 和昨天做差集

import json, pathlib

def track(username):
    snapshot = pathlib.Path(f"{username}_followers.json")
    current  = get_followers(username)

    if not snapshot.exists():
        # 第一次跑, 还没有可比对的基准
        snapshot.write_text(json.dumps(sorted(current)))
        print(f"已保存基准: {len(current)} 个粉丝")
        return

    previous = set(json.loads(snapshot.read_text()))

    gained = current - previous
    lost   = previous - current

    print(f"新增 {len(gained)} 个, 取关 {len(lost)} 个")
    for uid in lost:
        print(f"  取关: {uid}")

    snapshot.write_text(json.dumps(sorted(current)))

整个追踪器就这些。每天跑一次,你就有了一份完整的"谁来了、谁走了"的历史。

第三步 —— 把 ID 还原成人

差集给你的是 ID。要显示昵称,只查发生变化的那几个:

def describe(user_ids):
    """把少量 ID 还原成资料。只对差集调用这个。"""
    r = requests.get(
        f"{BASE}/v1/batch/user_info",
        params={"ids": ",".join(str(i) for i in user_ids)},
        headers={"X-API-Key": KEY},
        timeout=60,
    )
    return r.json()["data"]

如果 4 个人取关,这就是一次请求查 4 份资料 —— 而不是 5 万份。

这种批量查正是我们批量接口的用途 —— 一次调用,多个 ID。


一个好的追踪器该记什么

差集跑通之后,有意思的部分在于你保留什么:

时间。 取关是会扎堆的。如果某条推文发出后一小时内走了十一个人,那说明的是这条推文的问题,而不是你的受众整体有问题。

是谁,而不只是多少个。 掉一个 200 粉的账号和掉一个 20 万粉的账号是两回事。在做差集的那一刻把粉丝数一并记下来,你就能给它们加权。

方向变化。 关注→取关→又关注,这种行为和一次性离开完全不同。只有基于集合的追踪器才看得见这件事。

互关状态。 把粉丝集合和关注集合交叉一下,互关关系就白送给你了 —— 同样两份列表,多做一次集合运算而已。


多久跑一次?

对大多数账号,每天一次是正确的默认值,原因不太直观:X 的粉丝列表在时间上并不是完全稳定和有序的。 每五分钟拉一次,你会看到一些账号忽然出现又忽然消失,而它们其实既没关注也没取关你。那些是假象,只会把你的日志塞满误报。

每日快照的间隔足够长,列表已经稳定下来了。如果你确实需要更细的粒度,可以每小时跑,但要加一条规则:一个账号必须在连续两次快照里都缺席,才判定为取关。这一条规则能消掉绝大部分噪声。

对超大账号还要留意翻页成本:5 万粉丝按每页 200 条算,一次快照 250 个请求。每天一次没问题;每五分钟一次就是每天 7.2 万个请求,而换来的信息根本没变。


追踪别人的账号

上面所有做法对任何公开账号都成立,不限于你自己的。反正读的都是公开的粉丝列表 —— 代码一个字都不用改,只换 username。

这其实是更常见的商业用法:看谁开始关注了竞品、发现某个行业人物关注了一家新公司、捕捉一批账号同时聚拢到某个人身上的那一刻。

⚠️ 有一条边界要说清楚:这只对公开账号有效。受保护的账号不对外暴露粉丝列表 —— 对你、对任何人都一样,任何 API 都改变不了这一点。如果某个工具声称能做到,那它要么在骗你,要么在做你不会想参与的事。


大家会问的问题

能看到具体是谁取关了我吗? X 自己不给 —— 它有意不暴露这个。办法是比对你自己的粉丝快照,也就是上面代码做的事。

我查别人的粉丝,对方会收到通知吗? 不会。读取公开粉丝列表不是一个可见动作,不产生任何通知。

怎么自动追踪粉丝和取关? 把差集脚本挂到定时任务上 —— cron、GitHub Action、定时触发的 Lambda 都行,脚本本身不用改。

我之前没记录,现在能查出谁取关了吗? 不能。取关只能靠比对发现,所以必须有基准。今天的快照就是明天的基准 —— 越早开始越早有用。

怎么查某个人关注了谁? 把粉丝接口换成关注接口,同样的做法。差集逻辑一模一样。

所谓的"粉丝检查器"是什么? 基本就是上面这套的托管版 —— 帮你存快照、用界面展示差集。自己搭一个下午就够,而且历史数据在你自己手里。

能追踪粉丝数的变化曲线吗? 能,而且是顺带的:每次运行的 len(current) 就是时间序列。真正事后补不回来的是集合,数字随时能从集合算出来。

最多能追踪多少粉丝? 受翻页量限制,没有硬性上限。每页 200 条,10 万粉的账号一次快照 500 个请求。

能用来找精准粉丝吗? 可以 —— 拉一个受众与你目标重合的账号的粉丝列表,你就得到了一批已经对这个话题感兴趣的人。之后按粉丝数或简介关键词筛选即可。

为什么我的追踪器报了根本没发生的取关? 几乎都是翻页被截断。某次运行提前结束的话,它没拉到的每个粉丝都会看起来像取关。检查一下你是不是在跟 next_cursor 到空,而不是遇到短页就停。

能看到谁访问了我的主页吗? 不能。X 不对任何人暴露主页访问数据,也没有对应的接口。任何声称能给你这个的工具都是编的。

取关之后又关注回来,能看出来吗? 能,前提是你存的是集合而不是数字 —— 你会看到他离开、然后重新出现。基于计数的追踪器则完全看不到。

怎么查推特上谁的粉丝最多? 那是另一个问题,需要的是排行而不是差集。做法是拉一批候选账号的资料,按 followers_count 排序。

有免费的做法吗? 代码是免费的,数据不是。你总得有个粉丝列表的来源,而 X 官方接口按读取次数收费。无论走哪条路,都要为翻页量做预算。

查 X 的取关和查推特的一样吗? 完全一样 —— X 和推特是同一个平台、同一批数据,改名没有改变任何做法。

能同时追踪多个账号吗? 可以。脚本接收一个 username,循环一遍就行。每个账号存一份独立快照,差集互不干扰。

如果对方是被封号而不是取关呢? 他会从列表里消失,所以单纯的差集会报成取关。如果这个区别对你重要,把 lost 集合里的 ID 拿去查一下 —— 被封的账号查不出有效资料。

怎么查推特粉丝数? 它就在资料页上。 ★一个调用就能拿到任何公开账号的粉丝数★,你自己的或别人的。

推特有实时粉丝数吗? 按间隔轮询资料页。 ★"实时"就是你的轮询频率★ —— 没有任何端点会把粉丝数变化推给你。

怎么看粉丝数历史? ★只有你自己记录过才行。★ 平台不为你保存历史 —— 一个计数是一次读数,不是一个序列。

能拿到历史粉丝数吗? 不能追溯。 ★这就是贯穿本页的那个不对称:往前捕获极其简单,往回重建根本不可能。★

怎么画粉丝增长曲线? 每天存一次读数,再把序列画出来。 ★单个数字没有任何可比对象。★

粉丝计数器是什么? 就是循环读取资料页。 ★每一个都是这么工作的★,不管界面看起来像什么。

怎么长期追踪粉丝统计? 按固定间隔采样并存下每一次。 ★间隔必须恒定★,否则这个序列衡量的是你自己的调度节奏。

能看到谁取关了我吗? 只能靠比对快照 —— ★没有取关通知,也没有取关者名单★。

能搜索我的粉丝吗? 把列表取回来在本地过滤。 ★不存在跨粉丝的服务端搜索。★

怎么分析我的粉丝? 把带完整资料的列表拉下来,再按粉丝数、简介或活跃度分层 —— 识别不活跃账号。

粉丝数包含不活跃账号吗? 包含。 ★计数就只是计数★ —— 它不说明有多少是真实或活跃的。

我的粉丝数为什么会波动? 正常的自然流失,加上平台定期清理。 ★每天小幅变动是正常的,不值得做出反应。★

推特粉丝追踪是什么? 按计划记录粉丝数和粉丝列表。 ★平台不存历史,所以"追踪"是你做的事,不是你取回来的东西。★

有粉丝统计工具吗? 任何存每日快照的工具都是。 ★没有一个能给你"你开始之前"的历史。★

能拿到粉丝数历史吗? ★只有你记录过的。★ 不存在可供请求的历史序列 —— 这就是贯穿本页的那个不对称。

能看别人账号的历史粉丝数吗? 同一个答案 —— ★你追踪过就有;追溯地要就没有★。

怎么画粉丝增长曲线? 每天存一次读数,再把序列画出来。 ★单个数字没有任何可比对象。★

粉丝计数器是什么? 就是循环读取资料页。 ★每一个都是这么工作的★,不管界面看起来像什么。

粉丝数每天都会波动吗? ★会,而且小幅变动是正常的★ —— 自然流失加上平台定期清理。

怎么衡量粉丝增长率? 两次快照的差值,除以天数。 ★至少需要两次读数。★

能拿到粉丝的人群画像吗? 只能拿到每个粉丝资料页上公开的东西 —— ★简介、地点文本、粉丝数★。没有任何推断出来的。

怎么按粉丝数给我的粉丝排序? 把带完整资料的列表取回来,在本地排序。 ★不存在服务端排序。★

该多久拍一次快照? ★每天足够,而且间隔必须保持恒定★ —— 改动它会污染你自己的趋势线。


如果你不想自己搭这些管道

上面的追踪逻辑大概四十行。真正花时间的是它底下的东西 —— 不会截断的翻页、能区分限流和瞬时失败的重试,以及让这一切无人值守地长期跑下去。

这部分正是我们的 API 在做的事。一个接口,固定的按次价格,没有属于你的限流要管。轻量的 followers_ids 接口单次成本低于完整资料版 —— 当你每天要翻六位数的粉丝列表时,这个差价很实在。

有两种情况我们不收钱:请求还没发出去就被我们拒绝的(比如参数写错),以及我方原因导致的错误。你可以自己验证 —— 故意发一个错误请求,看余额动不动。

延伸阅读:X 接口报限流错误时该怎么办 · 怎么移除粉丝而不拉黑对方。