Files
douyin-pc/docs/2026-09-05-23-15-current-user-notifications.md
T
2026-09-06 01:00:17 +08:00

6.4 KiB
Raw Blame History

当前用户通知列表:调研、方案和安装

产出与范围

  • 账号:本次登录账号「抖咅求真」,脚本不绑定该账号。
  • src/get_notifications.py:独立命令入口,复用同目录 get_current_user.py 的登录态检查。
  • src/notifications.json:本次互动通知首批 10 条,含摘要、原始接口响应、分页游标。
  • src/test_notifications.py:离线可运行检查。
  • 范围为网页通知入口使用的 notice_group=960,不是私信、所有系统通知或完整历史。
  • 首批响应 has_more=1max_time=1783129215,不可当成全部通知。分页验证另获 7 条,保存于临时文件 /tmp/douyin-notifications-next.json,不包含在首批 10 条中。

调研记录

  1. 使用 browser-harness 连接现有 CDP 浏览器,页面为已登录的 /user/self,未执行登录。
  2. 通过 Accessibility.getFullAXTree 定位「通知」,使用 DOM.getBoxModel 和 CDP 坐标点击打开。
  3. 初始 performance resource timing 缓冲中只找到 /aweme/v1/web/external/notification/;该路径不能直接视为通知列表接口。
  4. 增大 resource timing 缓冲并清空旧记录后重新打开通知,确认实际列表接口是 /aweme/v1/web/notice/。加载更多节点曾在可视区域外,后来节点脱离 DOM,因此没有采用依赖节点 ID 的方案。
  5. 页面实际请求包含 is_new_notice=1notice_group=960is_mark_read=1count=10min_time=0max_time=0。浏览器同时添加大量设备/环境参数。
  6. 只传 device_platform、aid、is_mark_read、count 和时间参数,HTTP 200 但业务状态 status_code=5参数不合法。这不是登录丢失的证据。
  7. 补上 channel、is_new_notice、notice_group 后,在页面上下文 fetch 成功,HTTP 200 且 status_code=0。无需保存 Cookie、Token、签名或硬编码设备信息;没有证明这组参数中每一项都必需。
  8. 原始响应返回 notice_list=[],有效数据在 notice_list_v2。服务端 count=10 不保证每页恰好 10 条,下一页实得 7 条。
  9. 浏览器面板最初展示了评论获赞,但本次 is_mark_read=0 API 首批与它不完全一致;可能存在页面聚合、请求参数或缓存差异,未验证具体原因。因此结果明确按该 API 记录,不宣称完全等同 UI 可见列表。

已读副作用说明

调研打开通知面板时,站点自动发送过 is_mark_read=1 请求,可能已改变未读状态,无法恢复调研前状态。最终脚本固定 is_mark_read=0,不点击通知、不主动发送标记已读请求;这不是对服务端所有副作用的保证。

最终请求与解析

GET https://www.douyin.com/aweme/v1/web/notice/
  ?device_platform=webapp
  &aid=6383
  &channel=channel_pc_web
  &is_new_notice=1
  &is_mark_read=0
  &notice_group=960
  &count=10
  &min_time=0
  &max_time=0

通过 browser-harness 的 js() 在当前已登录抖音标签页内执行 fetch,浏览器管理凭证。不导出凭证,也不逆向实现签名。

  • Python 解析 response.text(),不在 JavaScript 中 JSON.parse 通知正文,避免 64 位 nid 精度丢失。摘要优先使用 nid_str。
  • 保存昵称、发送者 UID、时间(UTC+08:00)、类型、内容、已读字段和作品 ID。
  • 本次观察到 type=41 的作品获赞、type=33 的关注、type=31 的评论。未知点赞细分只写「点赞互动」,不猜测;完整原始数据用于后续补充解释。
  • 当前账号由 self profile API 动态获取,通知 user_id 必须匹配;错误时停止,不覆盖旧结果。
  • 输出先写临时文件再 replace,防止序列化/写入失败破坏上次结果。
  • JSON 含个人互动信息、用户公开资料及资源 URL,仅留在本地,不应公开提交或分享。

空白环境安装

依赖 Python 3.10+、uv、Chrome/Chromium 和 browser-harness。Python 脚本自身只用标准库,不需 requests、Playwright 等额外包。

# 已有 Python 时安装 uv;也可使用系统包管理器安装 uv
python3 -m pip install --user uv
# 本机实际工具位于 uv/tools/browser-harness;新环境可用以下方式安装
uv tool install browser-harness
# 确保 uv 的工具 bin 目录在 PATH 中
uv tool update-shell
browser-harness --doctor

上游安装说明: https://github.com/browser-use/browser-harness/blob/main/install.md 。本次尝试读取上游 raw 文档被抓取工具的 fake-IP SSRF 防护阻止;未做空白环境安装实测,版本差异以该安装说明为准。

Chrome 需允许 CDP localhost:9222。空白环境可启动专用用户数据目录,目录由使用者决定,不要指向已在使用的普通浏览器资料目录:

# Linux 示例;其他系统替换 Chrome 可执行文件路径
chromium --remote-debugging-port=9222 --user-data-dir="$HOME/.douyin-cdp"
export BU_CDP_URL=http://localhost:9222

CDP 仅供本机使用,不向公网开放。在此浏览器中手动登录抖音;账号登录丢失时必须由用户重新登录,脚本不会操作登录。选择标签页示例:

browser-harness <<'PY'
new_tab('https://www.douyin.com/user/self')
wait_for_load()
print(page_info())
PY

保持 src/get_notifications.pysrc/get_current_user.py 同目录即可搬到其他环境使用。不绑定当前工作目录、账号 UID、Cookie、Token 或原机器屏幕大小。

运行与分页

python3 src/get_notifications.py
python3 src/get_notifications.py --output /path/to/existing-directory/notifications.json
# 上一页 has_more=1 时,传入它的 max_time;分开保存,避免覆盖首批
python3 src/get_notifications.py --max-time 1783129215 --output /tmp/douyin-notifications-next.json
python3 src/test_notifications.py

默认只取一页,不自动扫全部历史,不并发抓取。下一页继续使用上次返回的 max_time,直到 has_more=0;若游标不前进则停止。遇到接口异常、空响应、验证要求应停止检查,不反复重试。没有实现私信、常驻监听、自动标记已读。

实测结果

  • python3 src/get_notifications.py:成功写入 10 条,has_more=1。
  • 第二页命令:成功写入 7 条,has_more=1max_time=1778130860;本次未继续扫描全部历史。
  • python3 src/test_notifications.py:通过,覆盖 64 位通知 ID、时间转换、关注/点赞摘要、业务异常、响应结构异常以及 is_mark_read=0 和分页参数。