Getting it into your agent
One page per mod, every tool's command on it. A separate URL per tool would split the same page into five that compete with each other.
npx agentmods add skills/clawcap/manobrowser/web-data-extractornpx skills add ClawCap/ManoBrowser --skill web-data-extractorgit clone --depth 1 https://github.com/ClawCap/ManoBrowserWhat it costs to keep this loaded
Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.
| Model | Per session | Once invoked |
|---|---|---|
| Fable 5 | $0.00067 | $0.03616 |
| Opus 5 | $0.00034 | $0.01808 |
| Sonnet 5 | $0.00013 | $0.00723 |
| Haiku 4.5 | $0.00007 | $0.00362 |
Grade A, and why
web-data-extractor scanned grade A with 0 findings against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured 2d ago.
A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.
Nothing flagged
None of the 26 patterns this scan looks for appear in this file: no shell pipes, no recursive deletes, no credential paths, no hidden text, no instruction-override or anti-refusal phrasing, no agent-config snooping. That is not a guarantee, it is the absence of the things that are checkable.
How it starts
The opening of the file, as written. The whole thing — 156 lines — stays where its author put it; the contents beside it link to each section on GitHub.
网页数据提取器
概述
此skill通过执行内联的 DOM 提取脚本,从网页中提取结构化数据。通过以下流程:
- 直接调用
mcp__browser__chrome_execute_script执行内联脚本(脚本内部会自动滚动页面触发所有懒加载内容) - 使用
async () => await (脚本)等待Promise完成并获取JSON结果 - 返回包含文本节点(带上下文)、链接、标题的结构化数据
🚨 最关键要求:
调用 mcp__browser__chrome_execute_script 工具时,必须完整传递步骤2中定义的 jsScript 参数,不能省略、简化或修改任何字符,否则会导致数据提取失败!
核心原则:自动触发数据加载,一次性提取所有结构化内容及上下文,智能过滤和优化数据。
前置要求:
- Chrome MCP服务器已启动并连接
- 无需外部插件或扩展
何时使用此Skill
当用户提出以下请求时调用此skill:
- 从当前网页提取数据
- 抓取网站中的结构化信息
- 获取产品详情、价格、评论或其他电商数据
- 提取社交媒体帖子、评论或互动统计数据
- 导出网页中的表格或列表数据
- 获取任何可见的结构化内容的JSON格式
触发此skill的用户请求示例:
- "提取这个页面的所有产品信息"
- "把这个表格的数据转成JSON"
- "抓取这个社交媒体帖子的内容"
- "获取这个页面的结构化数据"
- "这个页面上有什么数据?"
- "提取当前网页的内容"
数据提取流程
步骤1:验证Chrome MCP工具可用性
在提取数据之前,确认以下工具可用:
mcp__browser__chrome_execute_script- 用于执行JavaScript脚本 如果工具不可访问,告知用户需要启动并连接Chrome MCP服务器。
步骤2:执行提取脚本获取DOM数据
🚨 关键要求:必须完整传递下面的 jsScript 参数,不能省略、简化或修改任何部分!
直接调用 mcp__browser__chrome_execute_script 工具执行内联的提取脚本:
工具参数(必须严格按照下面的完整参数调用):
tabId: 目标标签页ID(可选,不提供则使用当前活动标签页)jsScript: 必须使用下面的完整脚本,一个字符都不能少 →async () => await ((async () => { 'use strict'; window.scrollTo({ top: 0, behavior: 'instant' }); await new Promise(resolve => setTimeout(resolve, 300)); const documentHeight = Math.max(document.body.scrollHeight, document.documentElement.scrollHeight, document.body.offsetHeight, document.documentElement.offsetHeight, document.body.clientHeight, document.documentElement.clientHeight); window.scrollTo({ top: documentHeight, behavior: 'smooth' }); await new Promise(resolve => setTimeout(resolve, 1500)); window.scrollTo({ top: 0, behavior: 'smooth' }); await new Promise(resolve => setTimeout(resolve, 1000)); function shouldSkipElement(element) { if (!element) return true; const skipClassPrefixes = ['vjs-', 'video-js', 'plyr', 'jwplayer', 'ad-', 'advertisement', 'cookie-', 'gdpr-']; if (element.className && typeof element.className === 'string') { const classes = element.className.toLowerCase(); if (skipClassPrefixes.some(prefix => classes.includes(prefix))) { return true; } } let parent = element.parentElement; let depth = 0; while (parent && depth < 3) { if (parent.className && typeof parent.className === 'string') { const parentClasses = parent.className.toLowerCase(); if (skipClassPrefixes.some(prefix => parentClasses.includes(prefix))) { return true; } } parent = parent.parentElement; depth++; } try { const style = window.getComputedStyle(element); if (style.display === 'none' || style.visibility === 'hidden' || style.opacity === '0') { return true; } } catch (e) { } return false; } function extractFilenameFromUrl(url) { if (!url) return url; try { const pathname = url.split('?')[0].split('#')[0]; const parts = pathname.split('/'); const filename = parts[parts.length - 1]; return filename || url; } catch (e) { return url; } } function extractImagesFromElement(element) { if (!element) return []; const images = []; const imgElements = element.querySelectorAll('img[src], img[data-src]'); for (let i = 0; i < imgElements.length; i++) { const img = imgElements[i]; const src = img.src || img.getAttribute('data-src'); if (src && src.trim() !== '') { images.push(extractFilenameFromUrl(src)); } } const allElements = [element, ...element.querySelectorAll('*')]; for (let i = 0; i < allElements.length; i++) { const el = allElements[i]; try { const style = window.getComputedStyle(el); const bgImage = style.backgroundImage; if (bgImage && bgImage !== 'none') { const matches = bgImage.match(/url\\(['"]?([^'"()]+)['"]?\\)/g); if (matches) { matches.forEach(match => { const url = match.replace(/url\\(['"]?([^'"()]+)['"]?\\)/, '$1'); if (url && url.trim() !== '' && !url.startsWith('data:')) { images.push(extractFilenameFromUrl(url)); } }); } } } catch (e) { } } return [...new Set(images)]; } function extractSVGPathsFromElement(element) { if (!element) return null; const paths = []; const pathElements = element.querySelectorAll('svg path[d]'); for (let i = 0; i < pathElements.length; i++) { const d = pathElements[i].getAttribute('d'); if (d && d.trim() !== '') { paths.push(d.trim()); } } return paths.length > 0 ? paths.join(' ') : null; } function extractTextWithContext(element) { if (!element) return []; if (element.tagName && ['SCRIPT', 'STYLE', 'NOSCRIPT', 'HEAD'].includes(element.tagName)) { return []; } let results = []; if (element.shadowRoot) { const shadowResults = extractTextWithContext(element.shadowRoot); results.push(...shadowResults); } if (element.childNodes && element.childNodes.length > 0) { for (let i = 0; i < element.childNodes.length; i++) { const node = element.childNodes[i]; if (node.nodeType === Node.TEXT_NODE) { const text = node.textContent.trim(); if (text) { const parent = node.parentElement; const grandParent = parent ? parent.parentElement : null; const greatGrandParent = grandParent ? grandParent.parentElement : null; if (shouldSkipElement(parent) || shouldSkipElement(grandParent) || shouldSkipElement(greatGrandParent)) { continue; } const nodeData = { text: text }; if (parent && parent.className) { nodeData.className = parent.className; } if (grandParent && grandParent.className) { nodeData.parentClassName = grandParent.className; } if (greatGrandParent && greatGrandParent.className) { nodeData.grandParentClassName = greatGrandParent.className; } if (parent) { const parentImages = extractImagesFromElement(parent); if (parentImages.length > 0) { nodeData.parentImages = parentImages; } } if (grandParent) { const grandParentImages = extractImagesFromElement(grandParent); if (grandParentImages.length > 0) { nodeData.grandParentImages = grandParentImages; } } let svgPaths = null; if (parent) { svgPaths = extractSVGPathsFromElement(parent); } if (!svgPaths && grandParent) { svgPaths = extractSVGPathsFromElement(grandParent); } if (!svgPaths && greatGrandParent) { svgPaths = extractSVGPathsFromElement(greatGrandParent); } if (svgPaths && svgPaths.length < 1000) { nodeData.svg = svgPaths; } results.push(nodeData); } } else if (node.nodeType === Node.ELEMENT_NODE) { const childResults = extractTextWithContext(node); results.push(...childResults); } } } return results; } function deduplicateImagesGlobally(nodes) { const urlCounts = new Map(); nodes.forEach(node => { ['parentImages', 'grandParentImages'].forEach(field => { if (node[field]) { node[field].forEach(url => { urlCounts.set(url, (urlCounts.get(url) || 0) + 1); }); } }); }); const seenUrls = new Map(); nodes.forEach(node => { ['parentImages', 'grandParentImages'].forEach(field => { if (node[field]) { node[field] = node[field].filter(url => { const totalCount = urlCounts.get(url) || 0; if (totalCount <= 2) { return true; } const currentCount = seenUrls.get(url) || 0; if (currentCount < 2) { seenUrls.set(url, currentCount + 1); return true; } return false; }); if (node[field].length === 0) { delete node[field]; } } }); }); return nodes; } function deduplicateNodesByClassNames(nodes) { const seenKeys = new Set(); nodes.forEach(node => { const hasClassNames = node.className || node.parentClassName || node.grandParentClassName; if (hasClassNames) { const key = (node.className || '') + '|' + (node.parentClassName || '') + '|' + (node.grandParentClassName || ''); if (seenKeys.has(key)) { delete node.className; delete node.parentClassName; delete node.grandParentClassName; } else { seenKeys.add(key); } } }); return nodes; } let textNodes = extractTextWithContext(document.body); textNodes = deduplicateImagesGlobally(textNodes); textNodes = deduplicateNodesByClassNames(textNodes); const result = { url: window.location.href, title: document.title, textNodes: textNodes }; window.extractedData = result; console.log('✅ v0.05'); return JSON.stringify(result); })())world:MAIN(在页面主上下文中执行)timeout:15000(超时时间15秒,因为包含智能滚动和数据提取)
What this file has done since we first saw it
Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.
- 2d ago First seen · 156 lines · 67 tokens per session scan A 824c5ee3e755
web-data-extractor is a skill published in the GitHub repository ClawCap/ManoBrowser (9 stars, last pushed 4mo ago), licensed MIT. It adds 67 tokens to every session and 3,616 once invoked, about $0.0003 per session on Opus 5. A static security scan graded it A with 0 findings. No closer match exists in the catalogue, so it is treated as the original; first seen 2026-08-31.
Other skills, from other repositories
aipex-browser
AI-powered browser automation using the AIPex Chrome Extension via MCP bridge. Use this skill when the agent needs to control a Chrome browser — navigating pages, clicking elements, filling forms, capturing screenshots, managing tabs, or downloading content — by connecting to the AIPex MCP bridge.
browser-relay
Control the Chrome the user already has open and logged in through the Browser Relay CLI, without launching a separate automation browser or taking over the foreground tab. Use when an agent needs to work with existing sessions, cookies, extensions, SSO or intranet pages, or a browser on another machine. Prefer the…
just-scrape
Search, scrape, crawl, extract structured data, and monitor web pages via the ScrapeGraph AI CLI. Use when the user asks to search the web, scrape a webpage, grab content from a URL, extract JSON from a site, crawl documentation or site sections, monitor a page for changes, inspect request history, check ScrapeGraph…
owb
Open Web Bridge (OWB) — drive the user's own real browser with the owb command. Read pages behind their existing logins, gather and cross-check information, fill forms, walk multi-step flows, debug their site, audit responsive/accessibility behavior, and capture or reverse-engineer network traffic. Use this whenever…
website-explorer
Discover website capabilities from user behaviors. Learn APIs and automate workflows.
website-explorer
通过用户行为发现网站能力,学习 API 并沉淀自动化流程.