Domain skill
feishu
Markdown synced from browser-harness domain skills.
- Host
- feishu
- Files
- 1
Agent prompt
Use this skill
Copy this prompt into your coding agent to make it enable browser-harness domain skills and read this exact domain folder before automating.
Set up https://github.com/browser-use/browser-harness for me if it is not already installed. If setup is needed, read `install.md` first to install and connect it to my real browser. Then read `SKILL.md` for normal usage and always read `helpers.py` because that is where the browser-harness functions are. Enable domain skills if they are not already enabled by setting `BH_DOMAIN_SKILLS=1` for browser-harness. Use the `feishu` domain skill from `agent-workspace/domain-skills/feishu/`. Read every markdown file for this domain before inventing an approach: - agent-workspace/domain-skills/feishu/docx-scraping.md Use those domain-skill notes to complete my task for `feishu` in my real browser. When you open a setup, verification, or task tab, activate it so I can see the active browser tab.
Skill contents
What the agent will read
飞书文档(Feishu Docs / docx)抓取
docx-scraping.md
- 抓 .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.
- 同一 wiki 空间内的兄弟文档只在正文里以富文本链接出现,document.body.innerText 拿不到 href——要拿链接得查 DOM:
- 正文渲染在一个内部 div 里,window.scrollY 恒为 0,window.scrollBy() 无效。先探测真正的滚动容器:
Show full markdown
抓 *.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:
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() 无效。先探测真正的滚动容器:
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 只返回当前渲染的部分。一次性读拿不到全文。做法:小步滚动 + 逐行去重累积。
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:
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
另外正文里普遍插入零宽字符,先清掉再比对:
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. 用截图补表格与配图,用文本做全文检索
两遍分开跑,不要在一个循环里同时做——截屏耗时会拖慢文本累积的节奏,容易漏块。