> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sorsa.io/llms.txt
> Use this file to discover all available pages before exploring further.

# 粉丝与关注

# 如何通过 API 获取 Twitter 粉丝和关注列表

公开 X（原 Twitter）账号的粉丝和关注列表，是平台上极具价值的数据集。粉丝列表说明谁对某个品牌、话题或人物感兴趣；关注列表则反映账号重视谁，包括其影响来源、竞争对手和信息来源。两者共同描绘账号周围的社交关系图谱。

Sorsa API 提供两个端点：`/followers`（谁关注了某账号）和 `/follows`（某账号关注了谁）。二者每次最多返回 200 份完整用户资料，并通过游标分页遍历完整列表。每个用户对象包含简介、粉丝数、推文数、所在地、认证状态、头像等。

本指南从最简单请求开始，介绍两个端点，并逐步涵盖生产规模的数据提取、筛选、受众重叠分析和分页策略。

> **免费开始：** 包括 `/followers`、`/follows` 和 `/verified-followers` 在内的所有 Sorsa 端点，都可使用初始赠送的 100 次请求：一次性赠送，无需信用卡，永不过期。每次最多返回 200 份资料，因此在购买套餐前，大约可获取某账号的前 20,000 位粉丝。

> **注意：** 更多提取方式和受众分析实例，请参阅博客上的 [Twitter 粉丝 API：获取粉丝和关注列表](https://api.sorsa.io/blog/twitter-followers-api)。

***

## 最简单的示例：获取粉丝

只需一次请求和一次响应，即可获取任意公开账号的第一页粉丝。

### cURL

```bash theme={null}
curl "https://api.sorsa.io/v3/followers?username=stripe" \
  -H "ApiKey: YOUR_API_KEY"
```

### Python

```python theme={null}
import requests

resp = requests.get(
    "https://api.sorsa.io/v3/followers",
    headers={"ApiKey": "YOUR_API_KEY"},
    params={"username": "stripe"},
)
for user in resp.json().get("users", []):
    print(f"@{user['username']} - {user.get('description', '')[:80]}")
```

### JavaScript

```javascript theme={null}
const resp = await fetch(
  "https://api.sorsa.io/v3/followers?username=stripe",
  { headers: { "ApiKey": "YOUR_API_KEY" } }
);
const { users } = await resp.json();
users.forEach((u) =>
  console.log(`@${u.username} - ${u.description?.slice(0, 80) ?? ""}`)
);
```

发送包含 API 密钥和用户名的 GET 请求。响应对象包含最多 200 份资料的 `users` 数组，以及用于分页的 `next_cursor`。

> **提示：** 通过[最新粉丝](https://api.sorsa.io/playground/recent-followers)工具或 [API Playground](https://api.sorsa.io/playground)，无需代码即可预览任意账号的粉丝。

***

## 最简单的示例：获取关注对象（订阅）

`/follows` 的用法相同，但返回用户关注的账号：

```bash theme={null}
curl "https://api.sorsa.io/v3/follows?username=stripe" \
  -H "ApiKey: YOUR_API_KEY"
```

```python theme={null}
resp = requests.get(
    "https://api.sorsa.io/v3/follows",
    headers={"ApiKey": "YOUR_API_KEY"},
    params={"username": "stripe"},
)
for user in resp.json().get("users", []):
    print(f"@{user['username']} ({user['followers_count']} followers)")
```

***

## 端点参考

两个端点都使用 GET，并支持相同输入选项。

### `GET /v3/followers`

返回**关注**指定账号的用户。

### `GET /v3/follows`

返回指定用户**正在关注**的账号。

### 输入参数（查询字符串）

| 参数            | 类型      | 必需  | 说明                                      |
| :------------ | :------ | :-- | :-------------------------------------- |
| `username`    | string  | 三选一 | 不含 `@` 的用户名，例如 `stripe`。                |
| `user_id`     | string  | 三选一 | 数字用户 ID，例如 `44196397`。                  |
| `user_link`   | string  | 三选一 | 完整资料 URL，例如 `https://x.com/stripe`。     |
| `next_cursor` | integer | 否   | 分页游标。将上一响应的 `next_cursor` 值原样传回，以获取下一页。 |

每次只提供 `username`、`user_id` 或 `user_link` 其中一种。

### 响应

```json theme={null}
{
  "users": [
    {
      "id": "1234567890",
      "username": "developer_jane",
      "display_name": "Jane Chen",
      "description": "Full-stack developer. Building things with APIs.",
      "location": "San Francisco, CA",
      "profile_image_url": "https://pbs.twimg.com/profile_images/...",
      "profile_background_image_url": "https://pbs.twimg.com/profile_banners/...",
      "followers_count": 4820,
      "followings_count": 312,
      "tweets_count": 1847,
      "favourites_count": 5231,
      "media_count": 89,
      "verified": false,
      "protected": false,
      "can_dm": true,
      "possibly_sensitive": false,
      "created_at": "2018-01-15T08:22:41Z",
      "bio_urls": ["https://janechen.dev"],
      "pinned_tweet_ids": ["1987654321098765432"]
    }
  ],
  "next_cursor": 1234567890
}
```

每个用户对象包含：`id`、`username`、`display_name`、`description`、`location`、`created_at`、`followers_count`、`followings_count`、`favourites_count`、`tweets_count`、`media_count`、`profile_image_url`、`profile_background_image_url`、`bio_urls`、`pinned_tweet_ids`、`verified`、`can_dm`、`protected` 和 `possibly_sensitive`。

每页最多返回 **200 个用户对象**。响应中存在 `next_cursor` 表示还有更多结果，将其作为下次请求的同名参数传回即可。字段缺失或为 null 时表示已到列表末尾。

***

## 分页获取完整粉丝列表

一次请求只返回一页。要收集完整列表，需循环使用 `next_cursor`，直到该字段缺失。

### Python

```python theme={null}
import requests
import time

API_KEY = "YOUR_API_KEY"

def get_all_followers(username, max_pages=50):
    """Fetch the complete follower list of a public account."""
    all_users = []
    cursor = None

    for page in range(max_pages):
        params = {"username": username}
        if cursor:
            params["next_cursor"] = cursor

        resp = requests.get(
            "https://api.sorsa.io/v3/followers",
            headers={"ApiKey": API_KEY},
            params=params,
            timeout=30,
        )
        resp.raise_for_status()
        data = resp.json()

        users = data.get("users", [])
        all_users.extend(users)
        print(f"Page {page + 1}: {len(users)} followers (total: {len(all_users)})")

        cursor = data.get("next_cursor")
        if not cursor:
            print("Reached end of list.")
            break
        time.sleep(0.05)  # stay under 20 req/s

    return all_users


followers = get_all_followers("stripe", max_pages=100)
print(f"\nTotal followers collected: {len(followers)}")
```

### JavaScript

```javascript theme={null}
const API_KEY = "YOUR_API_KEY";

async function getAllFollowers(username, maxPages = 50) {
  const allUsers = [];
  let cursor = null;

  for (let page = 0; page < maxPages; page++) {
    const params = new URLSearchParams({ username });
    if (cursor) params.set("next_cursor", cursor);

    const resp = await fetch(
      `https://api.sorsa.io/v3/followers?${params}`,
      { headers: { "ApiKey": API_KEY } }
    );
    if (!resp.ok) throw new Error(`HTTP ${resp.status}`);

    const data = await resp.json();
    allUsers.push(...(data.users || []));

    console.log(`Page ${page + 1}: ${data.users?.length || 0} followers (total: ${allUsers.length})`);

    cursor = data.next_cursor;
    if (!cursor) break;
    await new Promise((r) => setTimeout(r, 50));
  }
  return allUsers;
}

const followers = await getAllFollowers("stripe");
```

相同分页方式也适用于 `/follows`，只需更换 URL。

所有分页端点的详细行为请参阅[分页](https://docs.sorsa.io/zh-Hans/pagination)。

***

## 获取完整关注列表

只需替换端点，代码相同。查看账号关注谁，往往比查看其粉丝更能揭示信息：创始人的关注列表显示其重视的投资人、合作伙伴和竞争对手；意见领袖的关注列表则反映其信息来源。

```python theme={null}
def get_all_following(username, max_pages=50):
    """Fetch the complete list of accounts a user follows."""
    all_users = []
    cursor = None

    for page in range(max_pages):
        params = {"username": username}
        if cursor:
            params["next_cursor"] = cursor

        resp = requests.get(
            "https://api.sorsa.io/v3/follows",
            headers={"ApiKey": API_KEY},
            params=params,
            timeout=30,
        )
        resp.raise_for_status()
        data = resp.json()

        users = data.get("users", [])
        all_users.extend(users)

        cursor = data.get("next_cursor")
        if not cursor:
            break
        time.sleep(0.05)

    return all_users


following = get_all_following("naval", max_pages=20)
print(f"@naval follows {len(following)} accounts")

# Sort by follower count to see the biggest names
following.sort(key=lambda u: u.get("followers_count", 0), reverse=True)
for u in following[:10]:
    print(f"  @{u['username']} ({u['followers_count']:,} followers)")
```

***

## 实际应用

### 按资料条件筛选粉丝

原始列表有用，筛选后更便于行动。由于每个用户对象都包含完整资料元数据，你可以按任意属性细分受众，无需额外 API 调用：

```python theme={null}
followers = get_all_followers("competitor_handle", max_pages=20)

# High-value accounts: 1K+ followers, active (100+ tweets), not protected
qualified = [
    u for u in followers
    if u.get("followers_count", 0) >= 1000
    and u.get("tweets_count", 0) >= 100
    and not u.get("protected", False)
]
print(f"Qualified leads: {len(qualified)} out of {len(followers)} total")

# Accounts with websites in their bio (potential business leads)
with_websites = [u for u in followers if u.get("bio_urls")]
print(f"Accounts with website links: {len(with_websites)}")

# Filter by location keyword (self-reported)
in_usa = [
    u for u in followers
    if "usa" in (u.get("location") or "").lower()
    or "united states" in (u.get("location") or "").lower()
    or ", us" in (u.get("location") or "").lower()
]
print(f"US-based followers: {len(in_usa)}")
```

`location` 是用户自由填写的文本。若需要更可靠的国家级数据，可通过 `/about` 查询各账号的国家标记。完整流程见[受众地理分布](https://docs.sorsa.io/zh-Hans/Audience-Geography)。

### 发现竞争对手之间的受众重叠

获取多个竞争对手的粉丝列表，找出同时关注其中至少两家的用户。这些人多次主动选择关注同一主题，是市场中参与度较高的人群。

```python theme={null}
from collections import Counter

competitors = ["competitor1", "competitor2", "competitor3"]
all_ids = []

for handle in competitors:
    followers = get_all_followers(handle, max_pages=10)
    ids = [u["id"] for u in followers]
    all_ids.extend(ids)
    print(f"@{handle}: {len(followers)} followers collected")

# Count how many competitor lists each user appears in
counts = Counter(all_ids)
overlap = {uid: count for uid, count in counts.items() if count >= 2}
print(f"\nUsers following 2+ competitors: {len(overlap)}")
```

结合粉丝提取、简介搜索和社群分析的完整工作流，请参阅[发现目标受众](https://docs.sorsa.io/zh-Hans/target-audiences-Discovery)。

### 了解行业领袖关注谁

获取专家或思想领袖的关注列表，发现他们认为值得关注的人。这有助于找到细分领域账号、新兴声音和行业领袖依赖的工具。

```python theme={null}
following = get_all_following("pmarca", max_pages=10)

print(f"@pmarca follows {len(following)} accounts. Top by follower count:")
following.sort(key=lambda u: u.get("followers_count", 0), reverse=True)
for u in following[:15]:
    print(f"  @{u['username']} ({u['followers_count']:,} followers)")
    print(f"    {u.get('description', '')[:70]}\n")
```

***

## 认证粉丝

`/verified-followers` 的用法与 `/followers` 相同，但只返回带蓝色、金色或灰色认证标记的账号。主要适用于：

1. **直接筛选较知名账号**，无需获取完整列表后再处理。
2. **避免在大型账号上浪费请求**，尤其当认证用户占比很低时。为了找出 1,000 万粉丝账号中的 5,000 位认证粉丝，遍历全部列表需要 50,000 次请求；使用 `/verified-followers` 约 25 次即可获取同样的数据。

```bash theme={null}
curl "https://api.sorsa.io/v3/verified-followers?username=stripe" \
  -H "ApiKey: YOUR_API_KEY"
```

响应结构和分页与 `/followers` 相同，仍使用 `next_cursor` 迭代。完整详情请参阅 [API 参考](https://docs.sorsa.io/zh-Hans/api-reference/users-data/verified-followers)。

***

## 估算大规模 API 用量

每页最多返回 200 个用户对象，规划时可参考：

| 账号规模          | 所需页数  | 请求数   |
| :------------ | :---- | :---- |
| 1,000 位粉丝     | 5     | 5     |
| 10,000 位粉丝    | 50    | 50    |
| 100,000 位粉丝   | 500   | 500   |
| 1,000,000 位粉丝 | 5,000 | 5,000 |

按每秒 20 次计算，50 次和 500 次请求在速率限制下的理论最短时间分别为 2.5 秒和 25 秒。但单条游标链必须串行处理，每页依赖上一响应，因此实际时间还包括响应延迟、节奏控制和重试。对于数百万粉丝的账号，除非确实需要完整覆盖，否则可考虑抽样，例如前 50 页、约 10,000 位粉丝。

由于每次最多返回 200 份资料，粉丝提取消耗的请求较少。免费 100 次请求约可覆盖 20,000 位粉丝；Starter（每月 10,000 次请求）约覆盖 2,000,000 位；Pro（每月 100,000 次请求）约覆盖 20,000,000 位。完整价格见[价格](https://api.sorsa.io/pricing)。

***

## 数据时效与边界情况

**粉丝排序。** `/followers` 按 X 提供的顺序返回，通常为时间倒序，即新粉丝在前。前几页包含最近获得的粉丝。

**受保护账号。** 如果目标账号为受保护的私有账号，则无法访问粉丝和关注列表，端点会返回错误。

**粉丝计数与提取列表。** 资料中的 `followers_count` 是 X 维护的实时计数。由于停用、注销或最近移除的账号，可提取列表可能略有差异。大型账号可能相差几个百分点，不应对列表长度和 `followers_count` 做严格相等检查。这是平台层面的行为，并非 Sorsa 特有。

**资料数据是当前状态。** 每个用户对象反映请求时的资料，如当前简介、粉丝数和用户名，而非建立关注关系时的状态。数字 `id` 稳定不变，用户名则可能更改。

**超大账号的抽样。** 对于超过约 500,000 位粉丝的账号，前 50–100 页（最多约 10,000–20,000 位粉丝）有助于研究新粉丝。这是有序样本，不是整个受众的随机或代表性样本。除非有明确完整覆盖需求，通常无需全部提取。

***

## 后续步骤

* [发现目标受众](https://docs.sorsa.io/zh-Hans/target-audiences-Discovery)：结合粉丝提取、简介搜索、社群数据获取和内容分析
* [竞品分析](https://docs.sorsa.io/zh-Hans/Competitor-Analysis)：将粉丝和关注数据纳入竞品情报管道
* [受众地理分布](https://docs.sorsa.io/zh-Hans/Audience-Geography)：通过 `/about` 绘制粉丝国家分布
* [分页](https://docs.sorsa.io/zh-Hans/pagination)：大规模提取的通用分页模式
* [API 参考](https://docs.sorsa.io/zh-Hans/api-reference-guide)：`/followers`、`/follows`、`/verified-followers` 及全部 Sorsa 端点的完整规范
