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 skills add ClawCap/ManoBrowser --skill web-data-extractorgit clone --depth 1 https://github.com/ClawCap/ManoBrowserWrote this? Show the measurements
A badge with what this costs and how it scanned, read live from this page, so it follows the numbers instead of freezing them. Markdown for a README, HTML for a documentation site or a project page.
[](https://agentmods.dev/skills/clawcap/manobrowser/web-data-extractor)<a href="https://agentmods.dev/skills/clawcap/manobrowser/web-data-extractor"><img src="https://agentmods.dev/badge/skills/clawcap/manobrowser/web-data-extractor/github.svg" alt="Measured on agentmods" height="20"></a>Or the 80×15 button, for a site that already has a row of RSS and ATOM ones. Only the verdict fits; the numbers stay here.
<a href="https://agentmods.dev/skills/clawcap/manobrowser/web-data-extractor"><img src="https://agentmods.dev/badge/skills/clawcap/manobrowser/web-data-extractor.svg" alt="Reviewed on agentmods" width="80" height="20"></a>What 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.1 | $0.00067 | $0.03616 |
| Opus 5.5 | $0.00027 | $0.01446 |
| Sonnet 5.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 1mo 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.
- 1mo 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 6mo ago), licensed MIT. It adds 67 tokens to every session and 3,616 once invoked, about $0.0003 per session on Opus 5.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
Operate the user's existing, logged-in Chrome locally or on an explicitly connected remote machine. Read complete page content with actionable refs and links, perform grouped actions, and use screenshots in persistent browser sessions. Skip static public pages and pure REST APIs.
browser-bridge
Token-efficient Chrome tab inspection, interaction, and patching via local bridge extension (CLI: bbx). Reads live DOM, styles, console, network, and storage from a real Chrome tab with lower token cost than screenshots.
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…
control-chrome
Control and inspect the user's real Google Chrome through byob's local MCP tools. Use when Claude Code must work with an existing signed-in browser session, open or navigate tabs, understand a rendered page, click or type in web UI, fill forms, capture screenshots, inspect console or network activity, download page…
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…