BROWSER USE

- Browser Use Agents: give Browser Use a task and receive completed work. API V4 is current for new integrations.
- Browser Infrastructure: connect your agent or automation to managed browsers through SDK, REST, or CDP. Starts at $0.02/browser-hour.
- Developer tools: Open Source, Browser Harness, SDK, and MCP support the two products above.

[Developer Index](https://browser-use.com/index.md)
[Product Map](https://browser-use.com/llms.txt)
[Full Product Context](https://browser-use.com/llms-full.txt)
[Pricing](https://browser-use.com/pricing.md)
[Cloud Docs](https://docs.browser-use.com/cloud/quickstart)
[Open Source Docs](https://docs.browser-use.com/open-source/introduction)

---

# Feishu Docs scraper skill for AI agents

Source: https://browser-use.com/skills/feishu. One file from github.com/browser-use/browser-harness, MIT licensed. Written for browser-harness: code calls its helpers (http_get, js, goto_url). Sites change; these notes describe what worked when last updated.

---

<!-- https://github.com/browser-use/browser-harness/blob/main/agent-workspace/domain-skills/feishu/docx-scraping.md (updated 2026-10-09) -->

# 飞书文档（Feishu Docs / docx）抓取

抓 `*.feishu.cn/docx/<token>` 的正文与配图。连接用户已登录的 Chrome 即可，无需处理登录。

Current discovery uses the first hostname label, which can be the tenant name.
Read this file directly for Feishu document tasks when automatic discovery does not list it.

## URL 形状

```
https://<tenant>.feishu.cn/docx/<25位token>
```
同一 wiki 空间内的兄弟文档只在正文里以富文本链接出现，`document.body.innerText` **拿不到 href**——要拿链接得查 DOM：

```python
js("Array.from(document.querySelectorAll('a[href*=\"/docx/\"]')).map(a=>({t:a.innerText.trim(),h:a.href}))")
```

## 陷阱 1：滚动容器不是 window

正文渲染在一个内部 `div` 里，`window.scrollY` 恒为 0，`window.scrollBy()` 无效。先探测真正的滚动容器：

```python
FIND = """
(() => {
  let best=null,bh=0;
  document.querySelectorAll('div').forEach(el=>{
    const s=getComputedStyle(el);
    if((s.overflowY==='auto'||s.overflowY==='scroll') && el.scrollHeight>el.clientHeight+200){
      if(el.scrollHeight>bh){bh=el.scrollHeight;best=el;}
    }});
  window.__sc=best || document.scrollingElement;
  return best?{m:'el',sh:best.scrollHeight,ch:best.clientHeight}
            :{m:'win',sh:document.documentElement.scrollHeight,ch:window.innerHeight};
})()
"""
js(FIND)
```
实测返回形如 `{'m':'el','sh':8054,'ch':769}`。之后统一用 `window.__sc.scrollTop += N` 滚动。

## 陷阱 2：内容是虚拟化的

滚出视口的块会被卸载，`innerText` 只返回**当前渲染**的部分。一次性读拿不到全文。做法：小步滚动 + 逐行去重累积。

```python
import time
js("window.__sc.scrollTop = 0")
time.sleep(9)
seen, lines = set(), []
idle = 0
for i in range(500):
    for ln in js("document.body.innerText").split("\n"):
        s = ln.strip()
        if s and s not in seen:
            seen.add(s)
            lines.append(s)
    state = js("({top:window.__sc.scrollTop,sh:window.__sc.scrollHeight,ch:window.__sc.clientHeight})")
    if state["top"] + state["ch"] >= state["sh"] - 5:
        break
    step = max(1, int(state["ch"] * 0.8))
    js(f"window.__sc.scrollTop += {step}")
    time.sleep(0.75)
    current = js("window.__sc.scrollTop")
    idle = idle + 1 if current == state["top"] else 0
    if idle >= 4:
        raise RuntimeError("Document scrolling stopped before the end")
else:
    raise RuntimeError("Document capture reached its iteration limit")

```
- 步长取 `clientHeight * 0.8` 左右，留重叠，避免漏块。
- 每步之间 sleep ≥ 0.7s，否则新块还没渲染就读了。
- 加 stall 计数（连续 3–4 次 `scrollTop` 不变就 break），否则末尾会空转。
- 首屏要先 `sleep(8~10)`，飞书首次渲染慢。

**行级去重的代价**：正文里重复出现的短句（表头、「注意：」）只会保留第一次。对提取事实够用，对还原原文顺序不够。

## 陷阱 3：表格结构会丢

飞书表格在 `innerText` 里退化成一串无分隔的单元格文本，列关系全丢。文档里的关键规格常常就在表格中。**结论：表格靠文本抓不回来，只能靠截图看。**

## 陷阱 4：配图 URL 需要鉴权，别直接下

正文配图指向 `internal-api-drive-stream.feishu.cn/space/api/box/stream/download/v2/cover/...`，脱离浏览器会话直接 `http_get` 拿不到。

**可行做法：滚动截屏**，把整页按屏切成 PNG：

```python
capture_screenshot(f"{out}/{slug}_{i:03d}.png", max_dim=1800)
```
- `max_dim=1800` 必须加：2× 屏下原图超过 2000px，部分模型会拒收。
- 一份 8000px 高的文档约 12–21 张。
- 截屏同时保留了**表格结构和配图**，是补齐陷阱 3 的唯一手段。

## 噪声清单

正文抽取会混入这些固定 UI 文本，写清洗规则时直接丢弃：

```
External / Add Shortcut / Last modified: ... / Share / AI QuickView / Free trial
Comments (0) / Upload Log / Customer Service / What's New / Help Center
Keyboard Shortcuts / Backlinks (0) / Mentioned Docs (N) / Graph view
Suggestions are generated by AI. / This document hasn't been mentioned by others yet.
Be the first to like this
```

另外正文里普遍插入零宽字符，先清掉再比对：

```python
t = t.replace("​","").replace("﻿","").replace("⁠","")
```
文档标题尤其明显——`extract-meta.json` 里抓到的 title 前缀是几十个零宽字符。

## 推荐流程

```
1. new_tab(url) → wait_for_load() → sleep(9)
2. 探测滚动容器 → 回到顶部
3. 第一遍：滚动 + 累积 innerText  → full-text.txt
4. 第二遍：回到顶部，滚动 + capture_screenshot → shots/
5. 用截图补表格与配图，用文本做全文检索
```
两遍分开跑，不要在一个循环里同时做——截屏耗时会拖慢文本累积的节奏，容易漏块。
