使用个人主页快照跟踪 TikTok 粉丝增长
Advanced Data Extraction Specialist
TL;DR:
- TikTok 粉丝增长跟踪在开始收集时开始。 个人资料演员返回当前的公开计数,而不是历史序列。
- 每个观察都需要收集状态。 失败的收集和未改变的粉丝数量是不同的结果。
- 帐户身份应在用户名更改时得以保留。 将
account_id、sec_uid和观察到的unique_id一起存储。 - 增长是可比较快照之间的差异。 对相同帐户的连续有效计数进行相减,并保留两个时间戳。
- 粉丝增长并不识别其原因。 变化不能归因于某个视频或活动,除非有单独的证据。
- 免费开始。 新的 Scrapeless 帐户通过 Scrapeless Dashboard 包含免费信用。
引言:个人资料计数在第二次观察后变得有用
公开的粉丝计数是一个快照。只有在再次收集同一帐户并比较两个有效观察后,它才成为增长记录。
本教程使用 Scrapeless 个人资料演员、Python 和 SQLite 构建了一个小型 TikTok 粉丝增长跟踪管道。它保留帐户标识符,分别保存成功和失败的收集状态,从连续有效快照计算变化,并为创作者增长仪表板生成行。
底层个人资料字段和身份密钥在 TikTok 个人资料抓取教程 中介绍。
管道概览
| 阶段 | 操作 | 持久输出 |
|---|---|---|
| 定义 | 提供要追踪的帐户 | 帐户名册 |
| 收集 | 请求每个当前公开个人资料 | 原始 JSON 或错误记录 |
| 规范化 | 提取身份和统计信息 | 个人资料快照行 |
| 比较 | 连接连续成功快照 | 粉丝变化行 |
| 报告 | 画出水平和变化 | 增长仪表板输入 |
管道从开始收集的那天起便创建了历史。它不会从第一个存储观察之前的日期重建粉丝计数。
前提条件
- 一个来自 Scrapeless Dashboard 的 Scrapeless 帐户和 API 令牌
- 一个用户维护的公开 TikTok 用户名列表
- 适合报告需要的收集计划
SCRAPELESS_API_KEY中的一个有效令牌,用于下面的 API 块
完整示例有一个前提条件缺口,因为读者必须提供一个有效的凭据和帐户名册。本文不嵌入凭据或提供虚构的个人资料响应。
阶段 1:定义帐户名册
名册应包含一个稳定的内部键、当前用户名、跟踪该帐户的业务原因,以及记录是否保持激活状态。用户名是方便的请求输入,但不应成为唯一的数据库键。
scraper.tiktok.user.detail 演员接受 unique_id,而不带领导的 @。它的响应可以包括 account_id、unique_id、sec_uid、公开个人资料字段、帐户标志和包含粉丝、关注、朋友、喜欢、视频和喜欢视频计数的 statistics 对象。
将看起来像数字的帐户 ID 保留为字符串。保留所有三个标识符,以便稍后的用户名更改不会默默地创建一个新的历史序列。
阶段 2:捕获带时间戳的个人资料快照
每个收集尝试需要一个应用程序时间戳和状态。成功的行存储返回的标识符和统计信息。失败的尝试存储帐户键、尝试时间和一个简明的错误状态,而不将缺失的计数复制为零。
Python的 datetime 文档 描述了具有时区意识的时间戳。在存储中使用一个时区标准,并仅在报告层中应用显示时区。
TikTok的 官方用户信息文档 也将用户字段视为当前响应,而不是帐户历史馈送。因此,Scrapeless 管道构建了自己的观察历史。
使用 Scrapeless 开始抓取
使用 Scrapeless 为您的网络抓取和自动化工作流程加速!
今天注册并获得 5美元的免费信用 — 无需信用卡。立即在 Scrapeless Dashboard 领取您的免费信用。
阶段 3:分别存储成功和收集缺口
SQLite 支持一个紧凑的附加只读快照表。SQLite 表约束文档 解释了用于防止重复观察的复合键。
注意:以下代码需要一个在
SCRAPELESS_API_KEY中的实时 Scrapeless API 令牌和TIKTOK_USERNAMES中以逗号分隔的公开用户名。
python
import json
import os
import sqlite3
from datetime import datetime, timezone
from urllib.error import HTTPError
from urllib.request import Request, urlopen
ENDPOINT = "https://api.scrapeless.com/api/v1/scraper/request"
TOKEN = os.environ["SCRAPELESS_API_KEY"]
USERNAMES = [v.strip().lstrip("@") for v in os.environ["TIKTOK_USERNAMES"].split(",") if v.strip()]
def get_profile(username):
body = json.dumps({
"actor": "scraper.tiktok.user.detail",
"input": {"unique_id": username},
}).encode()
request = Request(
ENDPOINT,
data=body,
headers={"x-api-token": TOKEN, "content-type": "application/json"},
method="POST",
)
with urlopen(request, timeout=60) as response:
return json.load(response)
database = sqlite3.connect("tiktok-profile-history.sqlite3")
database.execute("""
CREATE TABLE IF NOT EXISTS profile_snapshots (
roster_username TEXT NOT NULL,
collected_at TEXT NOT NULL,
collection_status TEXT NOT NULL,
account_id TEXT,
unique_id TEXT,
sec_uid TEXT,
followers INTEGER,
following INTEGER,
likes INTEGER,
videos INTEGER,
error_code TEXT,
raw_json TEXT,
PRIMARY KEY (roster_username, collected_at)
)
""")
for username in USERNAMES:
collected_at = datetime.now(timezone.utc).isoformat()
try:
profile = get_profile(username)
statistics = profile.get("statistics") or {}
database.execute(
"INSERT INTO profile_snapshots VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
(
username, collected_at, "success",
str(profile.get("account_id") or ""), profile.get("unique_id"),
profile.get("sec_uid"), statistics.get("followers"),
statistics.get("following"), statistics.get("likes"),
statistics.get("videos"), None,
json.dumps(profile, ensure_ascii=False),
),
)
except HTTPError as error:
database.execute(
"INSERT INTO profile_snapshots VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
(username, collected_at, "failed", None, None, None, None, None, None, None,
str(error.code), None),
)
database.commit()
database.close()
collection_status 列保持一个可见的间隙。它防止报告查询将不可用观察视为没有关注者更改。
阶段 4:计算来自连续有效快照的增长
关注者增长是后期有效计数减去同一 account_id 的早期有效计数。保留开始和结束时间戳,两个源计数,差异以及经过的持续时间。
在连接时使用账户身份而非用户名。如果观察到的用户名在 account_id 保持稳定时发生变化,保留一系列并保留每个快照中记录的句柄。如果身份字段冲突,停止连接并将该行发送以供审核。
SQL 窗口函数可以配对成功的行而不覆盖原始观察:
sql
SELECT
account_id,
unique_id,
collected_at,
followers,
followers - LAG(followers) OVER (
PARTITION BY account_id ORDER BY collected_at
) AS follower_change
FROM profile_snapshots
WHERE collection_status = 'success' AND followers IS NOT NULL;
结果度量存储观察之间的变化。除非观察的时间间隔与报告标签相同,否则它不是每日增长率。
阶段 5:构建创建者增长仪表板
一个有用的仪表板在增长旁显示数据质量:
- 最新有效关注者数量及其收集时间
- 自上一个有效快照以来的变化
- 跨一个明确标记的报告间隔的变化
- 成功观察的数量和收集的间隙
- 当前观察到的用户名加上稳定的账户 ID
- 首个存储观察日期,定义历史边界
单独绘制关注者水平和关注者变化。水平图显示累积系列;变化图使收集间隙和突然差异更易于审查。
负责任地处理个人资料数据
公共个人资料统计数据仍然可以是个人数据。将账户名册限制于声明的目的,限制原始响应访问,并定义旧快照何时应被删除。NIST 隐私框架 提供了识别和管理收集风险的结构。
不要从个人资料响应中推断受众人口统计、关注者身份或增长原因。计数变化可能与一个活动或帖子同时发生,但巧合并不是归因。
Scrapeless 通过 Scraping API 暴露个人资料演员。在设置账户数量和时间表之前,请检查 当前定价页面。
结论:历史从记录的基线开始
TikTok 关注者增长跟踪需要稳定的账户身份、带时间戳的有效计数和明确的收集间隙。一旦基线存在,连续快照可以支持增长曲线,而无需声称不可用的平台历史或将变化归因于一条内容。
准备构建个人资料统计追踪器吗?
加入 Scrapeless Discord 或 Telegram 社区 以比较快照 схемы。 当账户名册准备好时,在 Scrapeless Dashboard 中创建一个账户。
常见问题
问:TikTok 关注者追踪器能恢复历史计数吗?
工作流程不能恢复收集开始前的计数。它的第一个成功观察成为后续比较的基线。
问:没有增长和收集失败有什么区别?
没有增长意味着两个有效快照包含相同的关注者计数。收集失败意味着后续计数未知,不应计算差异。
问:关注者增长能归因于一条 TikTok 视频吗?
关注者增长不能仅通过个人资料快照归因于一条视频。归因需要一个单独的实验或第一方活动证据。
问:工作流程是否暴露关注者身份或人口统计?
个人资料演员返回公共账户统计,而不是关注者列表或受众人口统计。
问:我需要管理代理或个人资料页面解析器吗?
演员在 API 请求背后处理其收集表面。调用者管理名册、时间表、存储、比较和报告。
问:收集公共关注者计数合法吗?
合法性取决于管辖权、用途、访问方法、数据和适用条款。尽量减少收集,记录目的,并为特定用途获得法律建议。
在Scrapeless,我们仅访问公开可用的数据,并严格遵循适用的法律、法规和网站隐私政策。本博客中的内容仅供演示之用,不涉及任何非法或侵权活动。我们对使用本博客或第三方链接中的信息不做任何保证,并免除所有责任。在进行任何抓取活动之前,请咨询您的法律顾问,并审查目标网站的服务条款或获取必要的许可。


