豆备 DOUBAK
← 开发日志

最不可替代的那批字节:自己上传的图

广播附图有三种写法,一个都猜不出来;以及第四次犯同一个错——从手上的样本推出一个封闭集合。

一部电影的封面,豆瓣没了也还能从别处找到。你自己拍的那张照片不能。 所以整份档案里最不可替代的就是这批字节:广播里的附图、日记正文里的插图。 这一趟抓下来 121 张本人上传的原图,26.3 MB,全是 JPEG,中位数 104 KB。

同一件事,豆瓣有三种写法

广播附图的结构在十几年里变过,而旧广播的旧写法就一直留在页面上:

  1. 一段 var photos 的 JSON,里面有 image.raw.url
  2. 同样的 JSON,但只有 image.large.url,没有 raw
  3. 更早的写法:一个 data-raw-src 属性

三种都在真实页面里同时存在。一种都不是想出来的,全是量出来的—— 这也是这个项目对选择器的规矩:每一个锚点都要注明它是对着什么量出来的。

那个作品缩略图不是你的图

第一个坑:容器的标记是 pics-wrapper / attachments-pic不是 group-pic。后者是标记类广播旁边那张作品封面缩略图 (包在 recommed-pics 里,target_typeilmen)—— 那是豆瓣的数据,不是你上传的东西。

把它算进去的后果:光第一份档案就冒出几十条假的「结构变了」告警。 告警多到一定程度就等于没有告警,所以这类误报要当真 bug 修。

第四次犯同一个错

第二个坑:图片的域名我写成了 img\d*.doubanio.com。 漏掉了 qnmob3.doubanio.com——它是真的,而且就在同一个页面里。

从手上的样本推出一个封闭集合,是这个项目反复翻车的地方,这是第四次。 前三次分别是:日记只有一种 URL 形状(其实两种)、个人主页一定会显示各个分类区块 (其实用户可以自己藏)、以及豆瓣的计数可以用来对账 (其实不行)。 每一次的形状都一样:n 很小,结论很确定。

别人的图不抓,而且要抓得住这条界线

自己的广播时间线里混着 30 张转发进来的、别人上传的图。 它们不在备份范围里——备份的是你的东西。所以每个抽取器都要限定在条目容器内, 广播还要按 data-uid 和账号自己的 userId 比一遍。

更微妙的是下游:解析器判断「哪些图算数」的条件,必须和扩展的一字不差。 而且两边错的方向不对称——

  • 解析器了:结构化数据里会引用抓取器从来没取过的字节,也就是一个死链。
  • 解析器了:档案里明明躺着的字节被静默丢掉,页面上什么都不剩。

所以有一个测试直接断言两个集合相等:结构化数据引用的图片, 与档案里 asset.status_photo 的行数,124 == 124。 这种「两处独立实现必须一致」的地方,不能靠记性,得靠断言。

← 更新:照片永远不会在增量抓取里出现 更早:公开测试开始 →