针对具体网站的网页抓取能力集合(百度/知乎/淘宝/京东等)。不在主 context 中展开具体网站列表,按需通过 capability_call 工具检索并加载对应 member;未命中或已有 member 失效时触发探索自动补全并沉淀为新 member。
Resources
6Install
npx skillscat add onewaymyway/mini-agent/browser-site-scraper Install via the SkillsCat registry.
SKILL.md
browser-site-scraper(generative-capability skill)
本 skill 不通过静态加载 references 的方式暴露内容,而是通过通用引擎mini_agent.skills.generative_capability.CapabilityEngine 按需检索、执行、
探索与固化。agent 在对话中调用本 skill,走的是 capability_call 工具
(见 src/mini_agent/tools/capability_call.py),不需要(也不应该)自己
构造 CapabilityEngine 实例。
调用方式
- agent 在对话中:调用
capability_call(skill_name="browser-site-scraper", request={...})工具。 - 代码/脚本中直接使用引擎(如手动调试、health_patrol 巡检脚本):
from mini_agent.skills.generative_capability import CapabilityEngine
engine = CapabilityEngine("path/to/browser-site-scraper")
result = engine.call({
"text": "帮我用百度搜一下 xxx",
"target": {"url": "https://www.baidu.com/s?wd=xxx"},
"query": "xxx",
})result.status 为 success / fail / not_implemented(命中/未命中都需要
触发探索、但探索本身失败——原因是目标底层原语未实现,或环境/站点导致真实
执行失败——时的如实反馈;阶段十八起 capability_call 会在 note 字段
据实区分这两种原因,不再是一句不分场景的固定文案,见 docs/skill-system- guide.md"已知限制"一节)。
依赖
- 底层通用浏览器操作能力:
browser-core(独立静态 skill,契约见.claude/skills/browser-core/SKILL.md;阶段十四起提供真实实现,见.claude/skills/browser-core/impl/)。browser-core是本 skill
现在唯一的浏览器操作依赖——阶段十五起,baidu/zhihu这两个已落盘的
人工预置 member 已经从直接依赖browser-cdp/src/searchers/*改为直接
调用browser-core/impl/session_manager.py(提取逻辑本身未变,只是换了
执行载体);探索链路调用的 7 个工具名同样对应browser-core契约。browser-cdp即将被移除,browser-core+browser-site-scraper是它
的替代方案(browser-core提供通用浏览器操作原语,browser-site- scraper提供"针对具体网站怎么用这些原语抓取"的 member 层),本 skill
不应再有任何路径指向browser-cdp目录。
已知限制
- 探索能力(
explore()/distill())需要真实tool_executor接入才能在
生产环境生效。capability_call工具会注入build_default_tool_executor(skill_dir=skill_dir)(阶段十二起如此,
阶段十四扩展为自动加载explorer.base_tools声明的静态 skill 自带
实现),browser-core下的 7 个工具名现在会真正执行(基于 CDP,见browser-core/HEADLESS_BROWSER_INTEGRATION.md),因此探索路径理论上
可以真正跑通——但实际成功与否取决于运行环境:- 需要本机/服务器有可用的 Chrome/Chromium/Edge(
launch_headless/launch_headed模式),或者提前手动启动好一个带--remote-debugging-port的浏览器(attach模式,需要登录的网站
应该用这种方式,由使用者手动登录好再交给探索子agent/member); launch_headed模式默认使用一份持久化、跨进程复用的用户数据目录
(见browser-core/SKILL.md"会话模式"一节),第一次手动登录过某个
网站之后,后续再用普通(有界面)浏览器打开会自动带着这份登录态,
不需要每次都重新登录;- 沙盒/CI 等没有可用浏览器的环境下,探索/member 执行仍会诚实失败并如实
返回not_implemented/浏览器层面的具体错误,不会伪造成功——baidu
member 额外做了"检测到验证码/风控拦截页时明确报错"的处理(而不是像
改造前那样把空结果误判成"成功但没抓到东西"),zhihumember 同理
检测登录墙; baidu/zhihu这两个人工预置 member 提取到 0 条结果、且没有命中已知
反爬/登录墙关键词时(阶段十七起),不再静默返回"成功但空结果",而是
返回失败并在error里附带调试快照(url/title/正文摘要),提示更可能
是选择器过期/页面结构变化/内容未渲染完成,而不是真的没有搜索结果;browser_extract_content是通用提取,不针对具体网站定制,复杂页面
结构下探索子agent可能需要多轮wait_for_selector/click/scroll
才能拿到符合intent_schema的数据,见browser-core/SKILL.md
"已知限制"一节。baidu/zhihu这两个人工预置 member 则是自己直接写
了针对性的提取 JS(不经过通用的browser_extract_content),所以不受
这条限制影响,但同样适用上一条"0 条结果视为失败"的处理。
- 需要本机/服务器有可用的 Chrome/Chromium/Edge(
已知限制(续):同域名重复 member(已修复根因,历史存量需手动清理一次)
- 背景与完整分析见
next_doc/browser_site_scraper_domain_dedup_and_matching_fix_plan.md:
同一个域名(典型如 arxiv.org 这种没有www.子域名前缀的裸域名站点)
曾经会被反复判定为"未命中",进而反复触发探索、堆出一串match.domain_pattern相同、只有keyword/description有细微差异的
重复 member(如arxiv_13~arxiv_20)。 - 根因是引擎
capability_engine.py::_domain_match对裸域名的通配符匹配
有 bug,已经修复(改为基于 URL host 的语义比较);同时distiller.py
新建 member 落盘时会检测同域名重叠并标记possible_duplicate_of,health_patrol.py新增duplicate_domain_pattern巡检项,日常巡检就能
发现这类重复,不用等人工偶然翻_index.json。 - [阶段 C 补充修复] 上面这条去重检测最初只接在脚本档
_atomic_persist()上,playbook 兜底档_persist_playbook_member()
是独立实现的对称代码,遗漏了这一步——导致所有经 playbook 产出的
member(_index.json里 description 带(playbook)后缀的那些)
完全不参与去重判断。同时registry.json/_index.json的落盘原本没
有并发写入保护,同一个未命中请求被并发探索多次时会互相覆盖、丢失
member 记录(真实案例:_index.json里 24 个 chartrow 系列 member,registry.json最终却只剩 1 条)。这两点已在distiller.py::_apply_domain_dedup()(两条持久化路径共用同一份去重
逻辑)与distiller.py::_SkillDirLock(串行化同一 skill 目录下的并发
落盘)里修复,完整记录见next_doc/browser_site_scraper_domain_dedup_and_matching_fix_plan.md
第 5 节。 - 如果你的环境里已经积累了这类历史重复(比如本 SKILL.md 描述场景下
真实出现过的 arxiv 系列 member),运行一次:
会把每组重复合并成一个 canonical member(python -m mini_agent.skills.generative_capability.health_patrol \ .claude/skills/browser-site-scraper --merge-duplicatessuccess_count最高者,
keyword 并集补入),其余标记为dead并从检索摘要移除——不会删除members/目录下的脚本文件,可审计、可回滚;不加--merge-duplicates
时默认只报告,不改动任何文件。
调试(阶段十六 / 阶段十八)
- 实际抓取失败时,
browser-core的失败返回会尽力附带debug字段
(url/title/正文摘要),另外可以直接调用browser_get_page_source/browser_get_debug_snapshot两个新增的调试原语拿到更完整的页面 HTML/
截图,见browser-core/SKILL.md"工具契约"一节。 - 默认会话模式(
auto)在连不上已有浏览器时,现在会退化为有界面
浏览器(而不是无头),方便需要登录的网站直接在弹出的窗口里手动登录;
纯后台场景可以在request.session.mode显式传"launch_headless"。 - "感觉还是打开了无头浏览器/没看到窗口"排查(阶段十八):
auto模式
只在目标端口没有浏览器监听时才会拉起新的有界面窗口,如果端口上已经有
浏览器在监听(哪怕是之前遗留的无头进程),会直接静默复用,不会弹新窗口。
用browser_list_sessions工具(或不经过对话、直接跑python .claude/skills/browser-core/manage.py list)看一下 9222 端口
现在是不是已经被占用;确认是遗留进程的话,用browser_close_session
(或manage.py close --port 9222)关掉,再重新发起请求,auto才会
真正拉起一个新的有界面窗口。 - 本地调试单个 member/URL 不需要走完整探索循环,可以用
dev/debug_run.py(开发期工具,不进_index.json检索):
失败时会打印带python .claude/skills/browser-site-scraper/dev/debug_run.py \ --member baidu \ --request '{"target": {"url": "https://www.baidu.com/s?wd=test"}, "query": "test"}'debug字段的错误详情;因为browser-core/impl/*.py
现在每次调用前都会清缓存重新加载(阶段十六"热更新"),编辑完脚本后
直接重跑同一条命令即可看到最新代码的效果,不需要重启任何进程。
更多信息
引擎设计、状态机、各版本演进历史见next_doc/generative-capability-skill-plan.md(本文件只描述"如何调用本
skill",不重复记录实施过程)。