朋友问我有没有能把评论批量存下来的工具。我说这种东西应该早有人做了。
找了几个可视化采集器,界面都不错,点几下配条规则就能跑。问题是跑不出东西。一个视频抓回来十几条,改了几轮规则还是十几条。改到第四五版我才想明白,不是我不会用。
那类工具是按“结构化列表页”设计的:你指给它看标题在哪、正文在哪、下一页按钮在哪,它照着往下翻。评论区不长这样。没有下一页按钮,滚到底了才加载下一批;楼中楼默认收着;搜索页不登录连结果都不给。
于是自己写了一个。起名观澜,出自“观水有术,必观其澜”。
抖音、B站、小红书、微博能用。快手写了但没跑通,最后说。
签名那关绕过去了
正常做法是抓包看请求,然后照着构造一个。卡在签名上:抖音要 a_bogus,B站要 w_rid,小红书要 x-s,都是前端 JS 现算出来的。想拿到就得把混淆过的代码逆出来,或者干脆起个 JS 引擎去跑它。前一条路慢,后一条路一旦平台改了算法就得重来。
那就别构造请求了。
改成用 Playwright 开一个真浏览器,正常打开搜索页、点进作品、往下滚,同时挂个监听,评论接口返回什么,我在旁边抄一份:
page.on("response", self._handle_response)
签名归页面自己管。慢是真慢,一个视频要跑一两分钟;好处是平台怎么改算法跟我没关系,只要接口路径和字段名不动,代码就还活着。
哪个 cookie 才算登录
这几个平台都得先登录,不登录的话搜索页要么跳走,要么只给你看两三条。所以程序开跑之前得确认自己是登录状态。
做法是直接读浏览器 profile 里那个存 cookie 的 sqlite 库,看某个 cookie 在不在。难的不是读,是挑哪个 cookie。
第一版我是拍脑袋定的,微博挑了 SUB,快手挑了 userId。跑起来日志写着“已检测到登录态”,然后搜索页零结果。查了一圈才发现这俩游客也有。
后来老实了:开无痕窗口,什么都不点,把 cookie 导一份出来;扫码登录,再导一份;两份 diff,多出来的那个才是。小红书是 id_token,微博是 SSOLoginState。快手那个叫 kuaishou.server.webday7_st,中间夹了个 day7,写死全名过几天就对不上,只能拿前缀去匹。
这种错误挺阴的。程序不报错,日志看着也正常,就是没数据。
说好的 238 条呢
第一次真正跑通那回,日志说这条视频接口显示共 238 条评论,我抓到 19 条。
先怀疑是翻页写错了。查下去发现接口自己在第 20 条就返回 has_more=0,手动在网页上滚也确实只有这么多。238 是把楼中楼算进去的总数,而楼中楼默认折叠,“展开 6 条回复”那句你不点,接口压根不会发。
加上展开,同一个视频 191 条。
展开这块比我想的费劲。B站那句“共 9 条回复”在一个普通 span 里,span 不可点,可点的是后面跟着的 bili-text-button,而它自己又套了一层 shadowRoot,得钻进去点里面的元素。微博是另一种绕法:评论区用虚拟滚动,“共 N 条回复”的链接在 DOM 里、样式上也可见,但坐标可能在文档外面几千像素的地方,点它一点反应没有。得先 scrollIntoView 把它挪回来,等页面重排完,再点。
这些都不是坐着能想出来的。
后来又打包了一版
写到这儿工具是给我自己用的,命令行够了。但一开始问我的那个朋友不写代码。绕一圈又回到起点:得让不碰命令行的人也能用。
于是拿 Tkinter 拼了个界面,PyInstaller 打成单文件 exe。
卡在体积上。Playwright 那套浏览器 450MB,打进去谁也发不出去。最后是浏览器不打包,界面上放个“一键安装运行环境”的按钮,头一回用点一下,程序自己去下。
下载源也换了。官方 CDN 在这边只有两百多 KB/s,还时不时整段整段地卡在零字节;换成 npmmirror 的镜像快了差不多一个量级。
有个细节我自己比较满意:浏览器、登录态、抓下来的数据、界面上次填的参数,全在 exe 边上放着,不往注册表和 AppData 里塞。不想要了,整个文件夹删掉就行。
快手没成
代码写完了,扫码也能过,会话 cookie 确实落到了 profile 里。但站点不认这个会话,回主站还是“立即登录”,一刷新就掉。
换了系统装的 Chrome,换了 Edge,一样。所以不是指纹伪装的问题,是平台那边专门处理了自动化环境。没绕过去。代码留着,哪天松了就能用。
README 里照实写了不可用。
代码在 github.com/mxlapan/guanlan,Releases 里有打好的 exe。
只抓公开评论,频率悠着点。
评论