feat(monitor): 博主的粉丝数,以及给作品起备注
Deploy VitePress site to Pages / build (push) Canceled after 0s
Deploy VitePress site to Pages / Deploy (push) Canceled after 0s

两件都是「作品栏里把这东西认出来」的延伸:

* **账号级指标**:作品列表只会说「这条涨了多少赞」,说不了「这个人整个
  账号的粉丝在涨还是在掉」。抖音的资料接口本来就有粉丝数/总获赞/作品数,
  每轮顺手记一条快照(`monitor_creator_stat`,粒度 = 任务×博主×轮次,
  和作品指标同形)。组头显示最近一条。

  快照在「一条作品都没采到」的早退**之前**落:作品列表被风控挡住的那一轮,
  正是「粉丝还在涨、但新作品没在发现」最该被看见的时刻。

* **作品备注**:博主备注回答「这个账号是谁」,这条回答「这条我要盯着」。
  一个博主底下常常只有一两件值得盯的作品,所以不能合并成一条。键取
  (platform, note_id),跨任务共用一份。

两边都守住同一条口径:**不知道就是 null,不写成 0** —— 0 在趋势图上是一条
砸到底的线,和「还没采到」是两回事。
This commit is contained in:
2026-10-10 18:09:03 +08:00
parent 0a88474c92
commit 20e672834c
15 changed files with 953 additions and 10 deletions
+58
View File
@@ -343,6 +343,64 @@ class MonitorCreatorAlias(MonitorBase):
updated_at: Mapped[int] = mapped_column(BigInteger, nullable=False)
class MonitorCreatorStat(MonitorBase):
"""博主的**账号级**快照:粉丝数 / 总获赞 / 作品数 / 关注数。
这是作品列表给不了的东西:作品级指标说"这一条视频涨了多少赞",账号级说"这个人
整个账号的粉丝是在涨还是在掉"。两者不互相替代。
粒度取 ``(任务, 博主, 轮次)``,和作品指标一样的形状 —— 于是趋势、差分、报表那套
现成的逻辑换个表就能用。
目前**只有抖音**会写它:小红书那条走的是爬虫子进程,而它的 ``save_creator()`` 在
教学版里是空函数,根本没落过创作者资料。所以表里只有抖音的博主。
"""
__tablename__ = "monitor_creator_stat"
__table_args__ = (
UniqueConstraint(
"task_id", "creator_hash", "run_id", name="uq_creator_stat"
),
)
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
task_id: Mapped[int] = mapped_column(
ForeignKey("monitor_task.id", ondelete="CASCADE"), nullable=False, index=True
)
run_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True)
creator_hash: Mapped[str] = mapped_column(String(64), nullable=False, index=True)
nickname: Mapped[str] = mapped_column(String(128), nullable=False, default="")
# 都可能为 None:平台没给就留空,**不要伪造成 0** —— 0 是"掉到零",和"不知道"
# 在趋势图上是完全不同的两回事。
fans: Mapped[Optional[int]] = mapped_column(BigInteger)
total_favorited: Mapped[Optional[int]] = mapped_column(BigInteger)
works_count: Mapped[Optional[int]] = mapped_column(BigInteger)
following: Mapped[Optional[int]] = mapped_column(BigInteger)
captured_at: Mapped[int] = mapped_column(BigInteger, nullable=False, index=True)
class MonitorNoteAlias(MonitorBase):
"""给**作品**起的备注。
和 ``MonitorCreatorAlias`` 是一对:博主那条回答"这是谁",这条回答"这条我要盯着"。
键取 ``(platform, note_id)`` —— 作品 id 本身就带平台语义,但显式带上 platform 才能和
博主备注用同一套查询形状。
"""
__tablename__ = "monitor_note_alias"
__table_args__ = (
UniqueConstraint("platform", "note_id", name="uq_note_alias"),
)
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
platform: Mapped[str] = mapped_column(String(16), nullable=False, index=True)
note_id: Mapped[str] = mapped_column(String(128), nullable=False, index=True)
alias: Mapped[str] = mapped_column(String(128), nullable=False, default="")
updated_at: Mapped[int] = mapped_column(BigInteger, nullable=False)
class MonitorSetting(MonitorBase):
"""Key/value store. Holds the XHS cookie for unattended runs."""