browser-harvestlisted
Install: claude install-skill yan-labs/yan-skills
# browser-harvest — 从登录态后台批量取数
很多值钱的数据在 SaaS 后台里:没有 API,或者 API 单独收费,或者导出按行扣点数。
界面就在那儿,人能看见,脚本却拿不到。本 Skill 解决的就是这段路。
**适用**:SEO/分析/广告/电商后台的报表页,需要登录态,数据以表格或列表呈现。
**不适用**:有开放 API 的服务(直接调 API)、静态公开页面(普通抓取即可)。
## 零、先决条件:必须用用户的真实浏览器
登录态在用户的浏览器里。任何"干净"的无头浏览器都没有会话,跑起来只会看到登录页。
- 用能连接用户真实浏览器的工具(Claude in Chrome 一类的浏览器扩展通道)。
- 内置的、隔离的预览浏览器**没有登录态**,不要用它去开后台。
- 如果同时存在两套浏览器工具,开工前明确���明用的是哪一套,别让用户以为你在他的浏览器里操作、实际却在一个空环境里空转。
## 一、四个必踩的坑
### 1. 现代后台的表格不是 `<table>`
高性能数据网格普遍用虚拟滚动:DOM 里只有可视区那几十行,而且常是**列式**结构——
行号、名称、数值各在自己的容器里。`querySelectorAll('tr')` 返回 0,`role="row"` 也常常没有。
**解法:按屏幕坐标重建行。** 取所有叶子元素的 `getBoundingClientRect()`,按 Y 聚类,行内按 X 排序。
两个关键细节:
- **锚点要选稳定的那一列**。用行号列做锚点会漏行(实测 100 行漏 23 行,因为行号单元格
和其它单元格偶尔落进不同的 Y 分桶)。改用**内容主列**(名称/关键词那一列)做锚点,
再收同一 Y ±11px 的其它单元格,才能 100% 还原。
- **一定要限定扫描范围**。整个 `document` 扫 `div,span,a` 单次约 2 秒,滚动循环几十次就爆超时;
改用 `TreeWalker` 且只在滚动容器内走,实测降到 **6ms**(快 300 倍)。写循环前先量单次耗时。
不同报表的列位不一样。写死 x 区间的版本换一张表就错位,**默认用列位自适应**(纯按 Y 聚类,
不假设任何列的 x)。
**URL 列是例外,必须从 `href` / `title` 属性读,不能从文本读。** 长 URL 在单元格里会换行成两行
并加省略号:文本本身是截断的,而且换行让这个单元格跨两个 Y 分桶,坐标法会把整行拆散、
再被 `minCells` 过滤掉——**这一类行会静默整批消失**。实测某报表 100 行里 78 行是长 URL,
坐标法只回收到 18 行,没有任何报错,肉眼看输出也很正常。属性里存的是完整 URL,一次全拿到
(用 `grabLinks()`)。判据:如果某报表的"页面/网址"列在结果里明显偏少,先怀疑这一条。
### 2. 数据出不了页面沙箱
页面里的 JS 能看到数据但**没有文件系统**;你的 shell 能写盘但**没有登录态**。中间只有三条通道:
| 通道 | 实测 |
|---|---|
| 代码执行工具的返回值 | 约 1KB 就截断,几十 KB 的表要分十几次取,慢且易错 |
| 剪贴板 `navigator.clipboard.writeText` | 常报 `NotAllowedError: Document is not focused`,还会把执行通道卡到超时 |
| **B