web-data-extractor
通过Chrome MCP服务器执行内置脚本提取页面结构化数据。当用户需要从当前打开的网页中提取、抓取或获取结构化数据时使用此skill,包括产品信息、社交媒体内容、表格、列表或页面上任何可见的结构化内容。
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
通过Chrome MCP服务器执行内置脚本提取页面结构化数据。当用户需要从当前打开的网页中提取、抓取或获取结构化数据时使用此skill,包括产品信息、社交媒体内容、表格、列表或页面上任何可见的结构化内容。
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Your hands in the user's real browser. Operate the user's own Chrome with their logged-in sessions — extract data behind login walls, reverse-engineer website APIs into reusable skills, and automate any browser workflow. Use when you need login-required data extraction, API reverse engineering, browser automation, or social media data collection. 给你一双手,像用户一样使用浏览器。在用户已登录的 Chrome 中工作——提取登录墙后的数据、逆向 API 生成可复用 Skill、自动化浏览器工作流。
根据用户需求,通过逆向网页API生成可复用的API取数Skill。适用于:图表数据(Canvas/ECharts/G2等前端渲染的图表)、需要登录态的平台数据、任何通过浏览器能看到但DOM中无法直接提取的数据。核心方法:鉴权探测决定架构 → 找到API endpoint → 逆向请求参数 → 验证数据 → 生成标准化Skill。
CDP-powered browser automation with UID-based targeting and background operations. Use when users ask to navigate websites, fill forms, take screenshots, extract web data, test web apps, or automate browser workflows. Supports file uploads, history navigation, and reliable element interaction. Trigger phrases include "go to [url]", "click on", "fill out the form", "take a screenshot", "scrape", "automate", "test the website", "log into", or any browser interaction request.
支持双模式生成浏览器自动化Skill:模式1-使用chrome-server MCP工具执行浏览器操作并从成功执行中生成可复用Skill;模式2-将DATASAVER录制工作流.json文件转换为可复用Skill。适用场景:1.自动化重复的浏览器任务(社交媒体发帖、网页抓取、表单填写)2.从浏览器自动化中创建可复用的工作流 3.为特定网站平台操作构建自定义Skill 4.将DATASAVER录制的浏览器操作转换为Claude Skill。
通用平台探索 Skill。使用 DataSaver Chrome MCP 工具对目标平台(URL/页面/模块)进行系统性探索,发现该平台可以做哪些用户操作类和数据提取类 Skill,输出 Skill 提案清单供用户确认,确认后按类型分流创建:API取数类调用 api-skill-builder,浏览器操作类调用 chrome-workflow-build。
| name | web-data-extractor |
| description | 通过Chrome MCP服务器执行内置脚本提取页面结构化数据。当用户需要从当前打开的网页中提取、抓取或获取结构化数据时使用此skill,包括产品信息、社交媒体内容、表格、列表或页面上任何可见的结构化内容。 |
此skill通过执行内联的 DOM 提取脚本,从网页中提取结构化数据。通过以下流程:
mcp__browser__chrome_execute_script 执行内联脚本(脚本内部会自动滚动页面触发所有懒加载内容)async () => await (脚本) 等待Promise完成并获取JSON结果🚨 最关键要求:
调用 mcp__browser__chrome_execute_script 工具时,必须完整传递步骤2中定义的 jsScript 参数,不能省略、简化或修改任何字符,否则会导致数据提取失败!
核心原则:自动触发数据加载,一次性提取所有结构化内容及上下文,智能过滤和优化数据。
前置要求:
当用户提出以下请求时调用此skill:
触发此skill的用户请求示例:
在提取数据之前,确认以下工具可用:
mcp__browser__chrome_execute_script - 用于执行JavaScript脚本
如果工具不可访问,告知用户需要启动并连接Chrome MCP服务器。🚨 关键要求:必须完整传递下面的 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秒,因为包含智能滚动和数据提取)⚠️ 特别强调:
jsScript 参数值必须完整复制,不能简化、不能用变量替代、不能省略任何部分⚠️ 重要说明:
async () => await (脚本内容) 来获取结果JSON.stringify() 包裹)脚本执行流程:
图片URL处理逻辑说明:
like_icon.png)className 去重逻辑说明:
className + parentClassName + grandParentClassName 组合生成唯一键返回数据格式(JSON 字符串,优化后):
{
"url": "https://example.com/page",
"title": "页面标题",
"textNodes": [
{
"text": "123",
"className": "like-count",
"parentClassName": "stats-wrapper",
"grandParentClassName": "video-info",
"parentImages": ["like_icon.png"]
},
{
"text": "456",
"parentImages": ["share_icon.png"]
},
{
"text": "274",
"svg": "M-4.644999980926514,4.482999801635742 C-7.25,7.818999767303467..."
},
{
"text": "评论"
},
{
"text": "1211"
}
]
}
🆕 SVG Path 字段说明:
svg 字段用于存储文本节点关联的 SVG 图标路径数据💡 如何利用 SVG Path 推断数字含义:
当文本节点包含 svg 字段时,应该根据 path 数据推断该数字代表的含义:
通过分析 svg 字段的 path 数据,可以更准确地判断纯数字节点代表的含义。
⚠️ 通用的语义映射规则: 语义字段 等价表达 阅读量 次观看、次播放、阅读、浏览、views、plays 点赞量 赞、点赞、likes、👍 评论量 评论、条评论、comments、replies 转发量 转发、分享、shares、retweets 收藏量 收藏、favorites、bookmarks