前言
做过微信私域运营或SCRM系统的开发者,几乎都会遇到同一个难题:如何把账号的好友列表稳定地同步到自己的系统里?微信官方不对个人号开放好友接口,第三方Hook方案则存在封号风险,且无法在服务器上稳定运行。好友数量一旦超过几千人,如何做分页拉取、如何识别新增好友、如何处理删除或拉黑——这些细节问题往往让开发者耗费大量时间踩坑。本文基于 WechatApi 个人微信API 平台,系统讲解好友列表接口的调用方式、分页机制与增量同步方案,附带可直接参考的代码示例。
一、好友列表同步的核心挑战
微信个人号的通讯录体量差异极大:普通用户可能只有几百个好友,私域运营账号则可能高达数千甚至接近微信官方上限(约5000人)。在设计好友列表同步功能时,以下几个挑战必须在架构层面提前考量。
全量拉取的性能问题。 直接一次性获取数千条好友记录,不仅响应时间长、超时概率高,还会对宿主设备产生明显压力。合理的做法是分页拉取,每页返回固定数量(如100条),分批写入本地数据库。
增量同步的识别问题。 全量同步只需在初始化时执行一次,此后应以增量模式运行:只拉取上次同步之后新增或发生变化的好友。如果不做增量区分,每次全量对比几千条记录会带来不必要的计算开销,并且在高频场景下容易产生脏数据。
删除与拉黑的检测问题。 微信本身不会主动推送"对方删除了你"的事件。检测好友关系变化,通常需要结合好友列表的全量快照与消息触达状态来综合判断,需要在业务层设计对应的比对逻辑。
多账号并发管理。 在私域运营场景中,往往需要同时管理数十甚至上百个微信账号。每个账号对应一个独立的 appId(设备ID),好友列表接口需要在请求参数中明确指定 appId,才能保证数据隔离与并发安全。
WechatApi 基于 iPad 协议实现微信接口能力,在服务器端稳定运行,规避了 PC Hook 方案的封号风险,也无需在本地安装客户端。对于需要处理上述挑战的开发者,这是目前生产环境中较为可靠的选择。
二、接口鉴权与请求规范
WechatApi 平台的所有接口均采用统一的 HTTP POST + JSON 规范,鉴权信息通过请求头传递,业务参数放在请求体中。
请求头格式
| 字段名 | 类型 | 说明 |
|---|---|---|
VideosApi-token | string | 控制台获取的 API Token,每个账户唯一 |
Content-Type | string | 固定为 application/json |
通用请求体参数
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
appId | string | 是 | 设备ID,登录微信账号后由平台分配,多账号并发时用于区分不同设备 |
pageIndex | int | 否 | 分页页码,从 0 开始,默认 0 |
pageSize | int | 否 | 每页返回条数,建议 50~200,默认 100 |
lastSyncTime | string | 否 | 增量同步时传入上次同步的时间戳(Unix 秒),仅返回该时间之后有变化的好友 |
通用返回体结构
所有接口均返回统一的 JSON 结构:
json{
"ret": 200,
"msg": "success",
"data": {
"total": 3268,
"pageIndex": 0,
"pageSize": 100,
"hasMore": true,
"list": [
{
"wxId": "wxid_xxxxxxxxxxxxxxx",
"nickname": "张三",
"remark": "客户-张三",
"avatar": "https://wx.qlogo.cn/...",
"sex": 1,
"city": "上海",
"province": "上海",
"addTime": 1700000000,
"isFriend": true,
"isBlocked": false
}
]
}
}
ret 为 200 表示成功,其余错误码(如 401 鉴权失败、500 设备离线)需在业务层做异常处理。hasMore 字段是分页控制的核心依据,只要为 true 就应继续请求下一页。
三、分页拉取:全量同步实现
全量同步通常在以下场景触发:首次接入某个微信账号、手动触发一次全量刷新、或者增量同步积累误差后的修复。
以下是一个 Python 实现的分页拉取示例,展示了完整的分页循环逻辑:
pythonimport requests
import time
API_BASE = "https://api.example-wechatapi.net" # 示意域名,以控制台实际地址为准
TOKEN = "your_videosapi_token_here"
APP_ID = "your_app_id_here"
HEADERS = {
"VideosApi-token": TOKEN,
"Content-Type": "application/json"
}
def fetch_all_friends(app_id: str) -> list:
"""全量分页拉取好友列表"""
all_friends = []
page_index = 0
page_size = 100
while True:
payload = {
"appId": app_id,
"pageIndex": page_index,
"pageSize": page_size
}
resp = requests.post(
f"{API_BASE}/friend/list",
headers=HEADERS,
json=payload,
timeout=30
)
result = resp.json()
if result.get("ret") != 200:
print(f"[ERROR] page={page_index}, msg={result.get('msg')}")
break
data = result["data"]
friends = data.get("list", [])
all_friends.extend(friends)
print(f"[INFO] 已拉取 {len(all_friends)}/{data['total']} 条")
if not data.get("hasMore", False):
break
page_index += 1
time.sleep(0.5) # 适当限速,避免触发频控
return all_friends
if __name__ == "__main__":
friends = fetch_all_friends(APP_ID)
print(f"[DONE] 共获取好友 {len(friends)} 人")
几个值得注意的实现细节:
- 限速:每页请求之间建议加 0.3~1 秒的间隔,避免触发平台或微信侧的频率限制。好友数量越多,拉取过程越长,稳定性比速度更重要。
- 异常重试:网络抖动或设备短暂离线可能导致某一页返回错误,应在外层加重试逻辑(最多3次,指数退避)。
- 断点续传:对于超大通讯录(3000人以上),可以将当前
pageIndex持久化到数据库,进程中断后从上次位置继续,而不必从第0页重新开始。
四、增量同步:只拉取新增好友
全量同步完成后,日常运营中只需要知道"上次同步之后新增了哪些好友"。通过 lastSyncTime 参数,接口会只返回 addTime 大于该时间戳的好友记录,大幅减少数据量和请求次数。
pythonimport requests
import time
import json
from pathlib import Path
API_BASE = "https://api.example-wechatapi.net"
TOKEN = "your_videosapi_token_here"
APP_ID = "your_app_id_here"
SYNC_STATE_FILE = f"/tmp/wechatapi_sync_{APP_ID}.json"
HEADERS = {
"VideosApi-token": TOKEN,
"Content-Type": "application/json"
}
def load_last_sync_time() -> int:
"""从本地状态文件读取上次同步时间"""
p = Path(SYNC_STATE_FILE)
if p.exists():
state = json.loads(p.read_text())
return state.get("lastSyncTime", 0)
return 0
def save_last_sync_time(ts: int):
"""保存本次同步时间"""
Path(SYNC_STATE_FILE).write_text(json.dumps({"lastSyncTime": ts}))
def fetch_incremental_friends(app_id: str, last_sync_time: int) -> list:
"""增量拉取:只获取 last_sync_time 之后新增的好友"""
new_friends = []
page_index = 0
current_time = int(time.time())
while True:
payload = {
"appId": app_id,
"pageIndex": page_index,
"pageSize": 100,
"lastSyncTime": str(last_sync_time)
}
resp = requests.post(
f"{API_BASE}/friend/list",
headers=HEADERS,
json=payload,
timeout=30
)
result = resp.json()
if result.get("ret") != 200:
print(f"[ERROR] {result.get('msg')}")
break
data = result["data"]
new_friends.extend(data.get("list", []))
if not data.get("hasMore", False):
break
page_index += 1
time.sleep(0.5)
# 同步成功后更新时间戳
if new_friends:
save_last_sync_time(current_time)
print(f"[INFO] 增量同步到 {len(new_friends)} 个新好友")
else:
print("[INFO] 无新增好友")
return new_friends
if __name__ == "__main__":
last_sync = load_last_sync_time()
print(f"[INFO] 上次同步时间: {last_sync}")
new = fetch_incremental_friends(APP_ID, last_sync)
增量同步的时间戳管理是整个方案的关键。推荐做法:
- 时间戳以服务端当前时间为准,而不是取返回数据中最后一条的
addTime。防止服务端时钟与本地时钟不一致导致遗漏。 - 状态文件或数据库中同时记录同步状态(成功/失败),失败时不更新时间戳,下次重新从上一个成功的时间点拉起。
- 定时任务频率:增量同步可以跑得比较频繁,5~15分钟一次是合理区间。全量同步建议每天凌晨执行一次作为兜底校正。
五、返回字段详解与数据库设计建议
好友列表接口返回的每条记录包含丰富的字段,合理利用这些字段可以支撑更多业务场景。
| 字段 | 类型 | 说明 | 运营价值 |
|---|---|---|---|
wxId | string | 微信唯一标识(wxid_xxx),稳定不变 | 主键,用于去重和关联 |
nickname | string | 好友当前昵称 | 定期更新,检测昵称变化 |
remark | string | 我方对该好友的备注名 | SCRM系统中的客户标识 |
avatar | string | 头像URL | 可缓存到自有CDN |
sex | int | 性别(0未知,1男,2女) | 用户画像分析 |
city / province | string | 城市/省份(用户自填,可能为空) | 地域分层运营 |
addTime | int | 加好友时间(Unix秒) | 增量同步的核心字段 |
isFriend | bool | 是否互为好友(对方是否也加了我) | 单向关注检测 |
isBlocked | bool | 是否被拉黑 | 清理无效好友 |
在数据库设计上,建议以 (appId, wxId) 作为联合主键,支持多账号数据隔离。同时在 addTime 和 sync_updated_at 上建索引,方便按时间范围查询。对于 SCRM 系统,可以在好友表上扩展自定义标签字段,与接口返回的原始字段分开存储。
如果你在做企业私域运营系统,这部分能力正是 WechatApi 微信API对接 和 微信二次开发 场景的核心需求之一,平台文档中对多账号并发场景有更详细的说明。
六、Shell 脚本快速验证接口
在正式接入之前,可以用 curl 快速验证接口连通性和返回格式,不需要写任何代码:
bashcurl -X POST "https://api.example-wechatapi.net/friend/list" \
-H "VideosApi-token: your_videosapi_token_here" \
-H "Content-Type: application/json" \
-d '{
"appId": "your_app_id_here",
"pageIndex": 0,
"pageSize": 5
}' | python3 -m json.tool
如果返回 ret: 200 且 data.list 中有好友数据,说明鉴权和设备绑定均正常。若返回 401,检查 Token 是否正确传入请求头;若返回设备离线类错误,需要先在控制台确认微信账号的在线状态。
登录控制台与申请 Token 的入口:https://newmanager.wechatapi.net/dashboard/
七、常见问题与注意事项
Q:好友列表拉取到一半中断了,需要从头开始吗?
不需要。保存当前 pageIndex 到本地状态,下次直接从中断的页码继续请求即可。建议每成功拉取10页就持久化一次进度。
Q:isFriend 为 false 是什么含义?
表示对方没有把你加为好友,也就是单向关注状态。这种情况下你仍然可以给对方发消息(对方未删除你),但对方无法主动给你发消息。在私域运营中,isFriend 为 false 的联系人通常需要单独处理(如发送添加提示)。
Q:addTime 的精度如何?能否依赖它做毫秒级精确增量?
addTime 精度为秒级。在设计增量同步时,建议将上次同步时间向前偏移 5~10 秒作为安全余量,避免因网络延迟导致边界数据丢失,代价只是少量重复记录(可在写入时用主键去重处理)。
Q:接口有频率限制吗?
平台侧有合理的频率控制,建议相邻请求间隔不低于 300ms。全量同步期间每页间隔 500ms 是稳健选择。如有更高并发需求,可联系平台申请提升配额。
Q:能否通过好友列表接口检测到"被删除"?
接口本身不推送删除事件。通常做法是:定期全量快照与本地数据库做 diff,若某个 wxId 之前存在、现在消失,则标记为"疑似被删"。结合发送一条消息后检测 isFriend 状态变化,可以进一步确认。这属于业务层的检测逻辑,与接口本身无关。
Q:iPad协议与PC Hook方案的好友列表接口有什么区别?
微信iPad协议 是在服务端模拟 iPad 客户端与微信服务器通信,数据来源与真实设备完全一致,且不依赖本地安装微信客户端,稳定性更高、更适合服务器常驻运行。PC Hook 方案需要在 Windows 机器上运行并注入微信进程,维护成本高,微信版本更新时频繁失效。对于需要长期稳定运行的生产系统,iPad 协议方案是更合理的选择。
小结
微信好友列表的稳定同步,看似简单,实际涉及分页控制、增量识别、时间戳管理、多账号隔离等多个工程细节。本文梳理了基于 WechatApi 平台实现全量分页拉取和增量同步的完整方案:全量同步用于初始化和定期校正,增量同步覆盖日常运营的新增好友识别,两者结合可以在保证数据准确性的同时最小化资源消耗。
如果你正在构建私域运营系统、微信客服机器人 或 SCRM 平台,好友列表接口往往是数据流的起点。WechatApi 平台文档(post.wechatapi.net)提供了完整的接口参考,控制台(newmanager.wechatapi.net/dashboard)支持在线测试与 Token 管理,可以作为开发验证的起点。
