6.4 KiB
当前用户通知列表:调研、方案和安装
产出与范围
- 账号:本次登录账号「抖咅求真」,脚本不绑定该账号。
src/get_notifications.py:独立命令入口,复用同目录get_current_user.py的登录态检查。src/notifications.json:本次互动通知首批 10 条,含摘要、原始接口响应、分页游标。src/test_notifications.py:离线可运行检查。- 范围为网页通知入口使用的
notice_group=960,不是私信、所有系统通知或完整历史。 - 首批响应
has_more=1,max_time=1783129215,不可当成全部通知。分页验证另获 7 条,保存于临时文件/tmp/douyin-notifications-next.json,不包含在首批 10 条中。
调研记录
- 使用 browser-harness 连接现有 CDP 浏览器,页面为已登录的
/user/self,未执行登录。 - 通过 Accessibility.getFullAXTree 定位「通知」,使用 DOM.getBoxModel 和 CDP 坐标点击打开。
- 初始 performance resource timing 缓冲中只找到
/aweme/v1/web/external/notification/;该路径不能直接视为通知列表接口。 - 增大 resource timing 缓冲并清空旧记录后重新打开通知,确认实际列表接口是
/aweme/v1/web/notice/。加载更多节点曾在可视区域外,后来节点脱离 DOM,因此没有采用依赖节点 ID 的方案。 - 页面实际请求包含
is_new_notice=1、notice_group=960、is_mark_read=1、count=10、min_time=0、max_time=0。浏览器同时添加大量设备/环境参数。 - 只传 device_platform、aid、is_mark_read、count 和时间参数,HTTP 200 但业务状态
status_code=5、参数不合法。这不是登录丢失的证据。 - 补上 channel、is_new_notice、notice_group 后,在页面上下文 fetch 成功,HTTP 200 且
status_code=0。无需保存 Cookie、Token、签名或硬编码设备信息;没有证明这组参数中每一项都必需。 - 原始响应返回
notice_list=[],有效数据在notice_list_v2。服务端 count=10 不保证每页恰好 10 条,下一页实得 7 条。 - 浏览器面板最初展示了评论获赞,但本次
is_mark_read=0API 首批与它不完全一致;可能存在页面聚合、请求参数或缓存差异,未验证具体原因。因此结果明确按该 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
¬ice_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.py 和 src/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=1,max_time=1778130860;本次未继续扫描全部历史。
python3 src/test_notifications.py:通过,覆盖 64 位通知 ID、时间转换、关注/点赞摘要、业务异常、响应结构异常以及 is_mark_read=0 和分页参数。