豆备 DOUBAK
← 开发日志

豆列:值钱的不是清单,是你写在每条上的那句话

扩展 1.1.0 开始抓豆列。实测一个真实账号 6 份、134 个条目,62 条带评语——其中一份是带价格和购买渠道的游戏消费流水。

扩展升到 1.1.0——次版本号而不是补丁号,因为多了一条路线, 抓的东西比 1.0.x 多。整条链路也跟着通了: 规范里多了第五类记录, canonical 里多了 doulists.ndjson生成的站点每份豆列一页。

清单是豆瓣的,评语是你的

豆列这东西,条目本身(标题、封面、评分、简介)全是豆瓣的目录数据—— 那些哪儿都有。只有挂在每条下面的那句评语是用户自己写的, 而豆瓣不导出它,档案里也没有第二处能推出它。

实测覆盖:6 份豆列、134 个条目、62 条带评语(单份是 24/25、9/15、9/12)。 其中一份是带价格和购买渠道的游戏消费流水—— 那种东西一旦没了,是真的没有别的地方能找回来。

关注的那半边不抓。 实测一份 25 条的样本:0 条评语, 每条都指向别人的影评——那是个纯书签夹,而且会混进豆瓣自己编的榜单 (另一套移动端渲染,实测一页 1.27 MB)。与「不抓社交外围」是同一条界线。

声称数取 null,宁可没有也不要假账

页面上写着「豆列(18) 片单(5) 书单(8)」,看起来正好可以拿来当分母。 但那是「创建 + 关注」的合计,而这条路线只抓创建的(实测 6 份)。

拿 18 当分母,档案里就会永久留下一笔「声称 18 / 抓到 6」的假账。 而档案是冻结的,假账改不掉,几年后读它的人只会得出「有 12 份被删了」。 不知道就写不知道。

一份豆列,被另一份豆列翻到头给停掉了

这是这次最值得记的一个,一个真的静默截断路径。

抓取有个停滞检测:连续几页什么都没有就收手(不能靠「没有新东西」来判, 一页全是重复是正常的)。但那个计数器按路线数, 而「豆列内容页」这一条路线底下装着 6 份各自分页的豆列, 队列又是广度优先的——于是实测的顺序是六份的第 1 页、再六份的第 2 页:

162349128 空 · 54002196 24条 · 45473911 20条
42193343 空 · 3913537 空  ← 连续第 2 个空页,判停滞

最后那份因此停在第 2 页,不再要第 3 页——它是被别的豆列的空页停掉的。 这一趟侥幸没丢东西(那几份本来就翻到头了),但换成一份第 3 页还有内容的, 就是静默截断;而这条路线连声称数都没有,漏了没有任何信号。

改法是:自带一串分页的路线,不看路线级的那个计数器, 改用两个判「这一串」的判据。广播和标记列表一条路线就是一串, 计数器对它们仍然是对的,不受影响。文档里同时写明: 再出现第二条这样的路线时,该做的是把停滞检测下沉到「串」那一层, 而不是继续加特例。

页面自己说它有几页,那就听它的

实测上一趟抓取:6 份豆列发了 18 次请求,其中 9 次拿回来是空页。 对一个「每个请求都要算账」的工具来说,那是九次注定落空的请求。

而答案就写在页面上:<span class="thispage" data-total-page="3">。 这是豆瓣自己的声明,不是我们从条目数推出来的—— 所以它不碰那条已经被证伪的「不满一页就是末页」 (游戏列表实测第 7、14、17 页只渲染 14/14/13 条)。

而且这个改动只可能比原来更早收手,不可能更晚: 有翻页器且它说到头了就收尾,没有翻页器则完全照旧。 「没有翻页器 ⇒ 只有一页」在这 6 份上确实成立,但那是 n=6, 这个仓库在「拿手上的样本推出封闭集合」上已经错过四次, 而这次猜错的后果是每份豆列只存前 25 条,且不报错。所以这一半不做。

私密判据只能用在详情页上

豆列有私密的,站点上会给它加一把锁。判据是详情页标题里的那个标记—— 但索引页也有自己的标题(内容是「我的豆列」), 把判据喂给它会一路走到「没有私密标记」→ 公开

错的答案,而且方向正是最坏的那个:把私密说成公开。 测试把这个错答案钉了下来,提醒下游必须先按用途把页面分开。

另外:移动应用(app)明确不支持

实测(2026-08-14):标记列表页还打得开,作品详情页全部 404—— 上游自己已经废弃了这个板块。

它从「还没查清」挪进了一张新的「明确不支持」表,带实测日期。 这两张表不能混:混在一起,一件已经有定论的事会永远显得像个待办, 下一个人还要再对着真实豆瓣点一遍——而那是这个项目最贵的一种确认。

而且「不支持这个分类」不等于「你的 app 标记备份不了」:标记会生成广播, 广播是照抓的。丢的只是那个豆瓣自己都不再提供的作品页。 规范那边只加注释、不删取值——爬虫不抓,与格式不认,是两件事

← 更新:私密的那一份,目录页上也得带锁 更早:上架当晚,别人替我逮到了两个 bug →