豆备 DOUBAK
← 开发日志

当好友注销了账号:从「页面不存在」到 WARC 里复活的高中同桌

一位高中好友注销了豆瓣,原始广播化作「呃...你想访问的页面不存在」,当年的转发引用沦为「[ 该广播仅作者本人可见 ]」;但翻开四年前打下的 Doubak WARC 档案,当年的同桌回忆、原始头像与 62 部书影音短评,原封不动地在本地醒来。这就是为什么我们坚持归档原始网页。

前几天,我想在豆瓣上找一位老朋友。

在关注列表(contacts)和被关注列表(rev_contacts)里反复翻了几遍,一无所获。 记忆里我们明明曾在很多条广播和电影下互动过,但人就像从数字世界里蒸发了一样。

凭借当年残存的线索,我终于顺着数字 UID 摸到了 TA 的豆瓣个人主页(douban.com/people/69305634/)。 然而迎面而来的,不是熟悉的动态,而是一块冰冷的灰色墓碑:

该用户已经主动注销账号。
注销时间:2025-05-31 13:13:34
>取消关注

注销时间定格在 2025 年 5 月底。 主动注销后,豆瓣系统抹掉了 TA 的一切公开展示。

坍塌的语境:「呃...你想访问的页面不存在」

我试着点开 TA 当年在 2018 年发出的那条广播原链接(douban.com/people/69305634/status/2181565157/)。 浏览器直接跳出了豆瓣经典的 404 页面:

呃...你想访问的页面不存在

觉得这里有点误导?要不,去豆瓣首页看看?或者搜索其他内容?

原帖已经彻底消失了。

面对注销后的空白主页,很多人的第一反应是去全球最大的互联网档案库(Internet Archive / Wayback Machine)碰碰运气。
确实,Internet Archive 曾在 2020 年 4 月 29 日尝试抓取过她的个人主页,但很可惜,抓下来的只是一个跳转登录界面的 302 响应:

https://www.douban.com/people/69305634/ | 21:48:59 April 29, 2020

Got an HTTP 302 response at crawl time

Redirecting to...
https://www.douban.com/accounts/login?redir=https%3A//www.douban.com/people/69305634/

因为公共档案馆的爬虫缺乏登录凭据,直接被豆瓣的访问限制挡在了门外。 对公域网络爬虫而言,像豆瓣这样充满登录墙与反爬限制的现代社交网络,几乎是一片无法渗透的黑洞—— 一旦用户主动注销,全网公域便彻底失去了 TA 曾经驻足的任何完整快照。

那么我自己的广播时间线呢? 顺着历史,我找到了自己在 2018 年 6 月 28 日发出的那条转发广播(status/2181605815):

“我也一直觉得我高三同桌就你了 哈哈哈哈 恃才傲物的咱俩一个人坐”

我的附言还在,照片还在。 但在今天的豆瓣线上页面上,上方被转发引用的原文区域,已经被替换成了一串冰冷的系统占位符:

[ 该广播仅作者本人可见 ]

语境被彻底切断了。 若干年后,如果一个不知情的人(甚至多年后记忆模糊的我本人)重新翻看这条广播, 只会看到一句突兀的「我也一直觉得我高三同桌就你了」,却再也看不到上一句是什么、是谁在回忆高三同桌、为什么会提到「男女不允许同坐」。 平台通过把原内容置换为 404 与遮罩,不仅抹去了离开者的痕迹,也在无声无息中侵蚀了留下者的记忆上下文。

从 2022 年的 WARC 琥珀与 GitHub 抓取历史中苏醒

万幸的是,豆备(Doubak)从第一天起就坚持抓取并封存标准的原始网页档案(WARC)。 而且早在这个独立备份体系成型前,作者就在自己的博客生成器仓库中完整留存了历史抓取的原始 HTML 网页。

翻开 GitHub 上的历史仓库:
👉 MewX/mewx.github.io-Generator 的 data/doubak/collector 历史抓取目录

在四年前的这份快照文件 20221225.1826_broadcast_p80.html 第 2336-2352 行中(以及 2022 年底打下的全量归档包 doubak-bundle-20221225T181500Z-98e6c6 广播切片 data-20221225T181500Z-98e6c6-00001.warc.gz 中), 那段已被线上永久抹杀的同桌对话,白纸黑字地公开留存在版本库中:

了凡当时的豆瓣头像
了凡 (UID: 69305634 · 2025-05-31 注销)
原头像地址:img9.doubanio.com/icon/u69305634-14.jpg(本地存档完好保存)

了凡(原广播 status/2181565157):
“高中,我们都不允许男女坐……不过我觉得高中最后阶段,老夏也算是我同桌了吧! @MewX”

MewX 转发附言(status/2181605815):
“我也一直觉得我高三同桌就你了 哈哈哈哈 恃才傲物的咱俩一个人坐”

顺着原始 HTML 的 DOM 结构深挖,我们甚至还原出了整场对话的起因:
当年引发这段感慨的,其实是友邻 29° 发的一条广播(status/2181490141),标题叫「这才是真正的天台喊话吧」,附带了整整 8 张高中生在天台上呼喊青春的组图。 了凡看到天台喊话后想起了高中岁月,便转发并 @ 了老夏;老夏随即转发附言,并将这 8 张图片一起转播到了自己的时间线上。

这 8 张当年的天台喊话照片,如今在豆瓣线上同样被层层设障,但豆备已经在样张库中将它们完整下载并持久化(支持点击查阅大图):

技术插曲:关于图片的 HTTP Referer 防盗链

为什么直接打开豆瓣图床的图片地址(如 img2.doubanio.com/view/status/...)会经常报错?
因为豆瓣 CDN(TencentEdgeOne)配置了严格的防盗链规则:如果请求头中不含 Referer,或者 Referer 来源不是 douban.com,服务器会直接掐断连接或返回 HTTP 418: I'm a Teapot / HTTP 403: Forbidden;只有带上 Referer: https://www.douban.com/ 才能正常获取。
这也是为什么任何依赖「仅保存图片链接」的轻量工具都会迅速失效——一旦账号注销或防盗链收紧,所有外链就会集体变成破损图标。而豆备通过抓取并将真实图片实体落地,彻底消除了对第三方 CDN 的任何依赖。

在随后的连续两年归档( 2023 年快照 与 2024 年快照 )中,这条广播都清晰无误地存在着。

而在由豆备静态站点生成器离线渲染的公开样张站上,这条广播在时间线上的记录同样得到了永恒的安放:
👉 sample.doubak.com/broadcast/2018-06.html#2018-06-28-202052

无论豆瓣线上如何删改、替换或者注销,这枚离线生成的页面不发出一个外部网络请求,永远停驻在那个 2018 年夏天的夜晚。

不止广播:书影音里 62 处未被磨灭的共鸣

广播只是一次偶发的对话,但在豆瓣这样的兴趣社区,真正的精神共鸣散落在书影音的长河里。

当一位用户注销后,豆瓣数据库将 TA 的所有历史评论重命名为 豆友69305634 或匿名散列,头像全黑;而在很多公域条目下,注销账号的短评甚至会被彻底折叠。

但由于豆备在登录态下抓取条目作品详情页时,忠实地将包含个人社交视角的原始页面写入了 catalog-*.warc.gz,详情页右侧边栏的「好友评价 / 我关注的人的评价」模块把这位好友当年的足迹完整冻结了下来。

在我的档案库里,一共有 62 部作品记录下了「了凡」当年的打分与真实短评。在我们的样张库和归档底片中,随时可以查阅这些珍贵的印记:

  • 读书 · 《1984》(豆瓣原页 subject/4820710):
    评价:★★★★☆(推荐,2017-12-29)· “读起来心肝颤……”
  • 电影 · 《活着》(豆瓣原页 subject/1292365):
    评价:★★★★★(力荐,2018-02-14)· “看不下去,太惨了”
  • 电影 · 《星际穿越》:
    评价:★★★★★(力荐)· “脑洞打开,这种片只有电影院看才过瘾”
  • 电影 · 《消失的爱人》:
    评价:★★★★★(力荐)· “看完不想结婚了,如果婚姻都到了这种地步,还能说什么呢?后面的日子,两个人互相折磨”
  • 电影 · 《大空头》:
    评价:★★★★☆(推荐)· “专业词汇比较多,说实话没怎么理解……( ・᷄ὢŕ惕)”
  • 电影 · 《花木兰》:
    评价:★★★★☆(推荐,2020-09-12)· “从哪里找了这么多中国景色,太厉害了。迪士尼免费给中国做的大外宣……”
  • 电影 · 《误杀》:
    评价:★★★☆☆(还行)· “翻拍得没有原版好,虽然原版我是后看的。结局为了主旋律作了生硬改动……”

以及《哆啦A梦》下的“怎么能少了你!”、《侏罗纪公园》下的“老片子的配音不是很喜欢…”……
62 部作品,跨越近十年。 这些文字在当下的互联网上已经难觅踪影,但在本地的 WARC 档案里,TA 的喜怒哀乐如同昨日。

技术底线:为什么「抽取字段」无法替代「原始网页」

这件事情在技术上给了我们极大的震撼与启发。

市面上绝大多数备份工具,其实现逻辑都是「抽取当下关心的字段」: 写几行正则或 CSS 选择器,提取 title、content、rating,然后导出一张 Excel 表格或者存入一个私有数据库。

抽取型备份的天然盲区:

在编写爬虫工具的那一刻,开发者会预设「哪些属于你的数据」—— 你的广播正文属于你,你的评分属于你;但别人被转播的话呢?别人的头像呢?条目侧边栏里好友的短评呢?
它们会被当作「第三方冗余」毫不留情地丢弃。 而一旦对方注销或平台屏蔽,这份只剩孤零零单向输出的抽取文件,立刻沦为一段失去上下文的断章残句。

这正是我们坚持将 WARC 作为豆备核心格式的根本原因:

  1. WARC 是不可篡改的「胶卷底片」: 它忠实保存了网络请求在 wire protocol 上的每一个字节。它不预设立场,不猜度你未来想看什么,而是把那一刻浏览器接收到的整个 DOM 视界完整封存;
  2. 冲洗权永远在本地: 今天的 doubak-data-parser 可能只提取了正文和标记动作; 但在未来任何时候,只要我们升级解析器,就能直接在本地离线重跑——无需任何网络请求,也不用担心页面变成了 404,就能随时从历史 WARC 底片中重新冲洗出「被转发引言」、「好友短评网络」与「互动树」。

后续演进

这次偶发的寻人经历,直接促成了我们对后续工具链的规划:

  • 支持抓取广播详情与评论互动(Issue #26): 目前扩展的广播路线是按时间线列表页抓取(broadcast.timeline)。列表页忠实记录了「这条广播有 1 条回应」以及转发引用的图文,但折叠在详情页里的多轮评论对话并未被拉取。 许多时候,广播本身可能只是一句感慨或一张图片,真正触动人心的话题交锋与老友接梗,往往全在下方的评论区里。 我们已经在扩展仓库建立了 Issue #26,计划针对存在回复的广播进一步抓取其详情页面(status/:id),把珍贵的评论对话也完整封存进 WARC;
  • 广播引言的结构化规范:在 doubak-data-specs 与 doubak-data-parser 中,推进 repost_source / quote 字段的解析标准,把广播被引用的作者、昵称与正文以第一等公民沉淀入 broadcasts.ndjson;
  • 静态站的引言卡片渲染:在 doubak-site-generator 中,补全转发广播的嵌套卡片视图,即使线上原文已逝,离线镜像依然能展现完整的对话脉络;
  • 条目好友互动的离线索引:探索从 catalog-*.warc.gz 中离线聚合「好友共读共看」视角的可能性。

互联网不是坚固的石碑,它是一片不断流动的沙滩。 账号会注销,帖子会被删,链接会 404,曾经形影不离的朋友也会在数字浪潮里悄然走散。

但只要你亲手把网页原样存进本地硬盘, 那个并肩坐在高三教室里、恃才傲物的阳光午后,就永远不会被风吹走。

← 更新:从一个名字到一张脸:账号头像的 WARC 归档与纯离线安全栅格化 更早:游戏评分成了访问者的:条目边界、缺席权威,与抓取中途的覆盖率 →