最不可替代的那批字节:自己上传的图
广播附图有三种写法,一个都猜不出来;以及第四次犯同一个错——从手上的样本推出一个封闭集合。
一部电影的封面,豆瓣没了也还能从别处找到。你自己拍的那张照片不能。 所以整份档案里最不可替代的就是这批字节:广播里的附图、日记正文里的插图。 这一趟抓下来 121 张本人上传的原图,26.3 MB,全是 JPEG,中位数 104 KB。
同一件事,豆瓣有三种写法
广播附图的结构在十几年里变过,而旧广播的旧写法就一直留在页面上:
- 一段
var photos的 JSON,里面有image.raw.url - 同样的 JSON,但只有
image.large.url,没有 raw - 更早的写法:一个
data-raw-src属性
三种都在真实页面里同时存在。一种都不是想出来的,全是量出来的—— 这也是这个项目对选择器的规矩:每一个锚点都要注明它是对着什么量出来的。
那个作品缩略图不是你的图
第一个坑:容器的标记是 pics-wrapper / attachments-pic,
不是 group-pic。后者是标记类广播旁边那张作品封面缩略图
(包在 recommed-pics 里,target_type 是 ilmen)——
那是豆瓣的数据,不是你上传的东西。
把它算进去的后果:光第一份档案就冒出几十条假的「结构变了」告警。 告警多到一定程度就等于没有告警,所以这类误报要当真 bug 修。
第四次犯同一个错
第二个坑:图片的域名我写成了 img\d*.doubanio.com。
漏掉了 qnmob3.doubanio.com——它是真的,而且就在同一个页面里。
从手上的样本推出一个封闭集合,是这个项目反复翻车的地方,这是第四次。 前三次分别是:日记只有一种 URL 形状(其实两种)、个人主页一定会显示各个分类区块 (其实用户可以自己藏)、以及豆瓣的计数可以用来对账 (其实不行)。 每一次的形状都一样:n 很小,结论很确定。
别人的图不抓,而且要抓得住这条界线
自己的广播时间线里混着 30 张转发进来的、别人上传的图。
它们不在备份范围里——备份的是你的东西。所以每个抽取器都要限定在条目容器内,
广播还要按 data-uid 和账号自己的 userId 比一遍。
更微妙的是下游:解析器判断「哪些图算数」的条件,必须和扩展的一字不差。 而且两边错的方向不对称——
- 解析器松了:结构化数据里会引用抓取器从来没取过的字节,也就是一个死链。
- 解析器严了:档案里明明躺着的字节被静默丢掉,页面上什么都不剩。
所以有一个测试直接断言两个集合相等:结构化数据引用的图片,
与档案里 asset.status_photo 的行数,124 == 124。
这种「两处独立实现必须一致」的地方,不能靠记性,得靠断言。