Skip to main content
Glama
Leviathangk

Playwright MCP Server

by Leviathangk
test-selector-optimization.js5.63 kB
/** * 选择器优化效果测试 * 对比优化前后的选择器长度和精确度 */ import { Client } from '@modelcontextprotocol/sdk/client/index.js'; import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js'; class SelectorOptimizationTest { constructor() { this.client = null; this.transport = null; } async connect() { console.log('🔌 连接到 MCP 服务器...\n'); this.transport = new StdioClientTransport({ command: 'node', args: [ 'build/index.js', '--browser', 'chromium', '--executable-path', 'D:\\Download\\chrome-win\\chrome-win\\chrome.exe', '--headless', 'false' ] }); this.client = new Client({ name: 'selector-optimization-test', version: '1.0.0' }, { capabilities: {} }); await this.client.connect(this.transport); console.log('✅ 已连接\n'); } async callTool(name, args = {}) { const response = await this.client.callTool({ name, arguments: args }); if (response.isError) { console.log('❌ 错误:', response.content[0].text); return null; } return JSON.parse(response.content[0].text); } async close() { await this.client.close(); } } async function main() { const test = new SelectorOptimizationTest(); try { await test.connect(); // 1. 创建会话 console.log('📝 创建浏览器会话...'); const session = await test.callTool('create_session'); const sessionId = session.sessionId; console.log(`✅ 会话 ID: ${sessionId}\n`); // 2. 访问一个复杂页面 console.log('🌐 访问淘宝首页(复杂页面)...'); await test.callTool('navigate', { sessionId: sessionId, url: 'https://www.taobao.com', waitUntil: 'networkidle' }); console.log('✅ 页面加载完成\n'); // 3. 获取页面结构 console.log('🔍 分析页面结构...\n'); const structure = await test.callTool('get_page_structure', { sessionId: sessionId, maxElements: 30 }); if (structure && structure.elements) { console.log(`找到 ${structure.totalFound} 个可交互元素\n`); console.log('=' .repeat(80)); console.log('选择器优化效果展示'); console.log('=' .repeat(80) + '\n'); // 统计选择器长度 const selectorLengths = structure.elements.map(el => el.selector.length); const avgLength = selectorLengths.reduce((a, b) => a + b, 0) / selectorLengths.length; const maxLength = Math.max(...selectorLengths); const minLength = Math.min(...selectorLengths); console.log('📊 选择器统计:'); console.log(` 平均长度: ${avgLength.toFixed(0)} 字符`); console.log(` 最长: ${maxLength} 字符`); console.log(` 最短: ${minLength} 字符\n`); console.log('📋 选择器示例(前 10 个):\n'); structure.elements.slice(0, 10).forEach((el, index) => { const text = el.text ? el.text.substring(0, 30) : '(无文本)'; console.log(`${index + 1}. ${text}`); console.log(` 选择器: ${el.selector}`); console.log(` 长度: ${el.selector.length} 字符`); console.log(` 层级: ${el.selector.split('>').length} 层`); console.log(''); }); // 分析选择器类型 const withId = structure.elements.filter(el => el.selector.startsWith('#')).length; const withClass = structure.elements.filter(el => el.selector.includes('.')).length; const levels = structure.elements.map(el => el.selector.split('>').length); const avgLevels = levels.reduce((a, b) => a + b, 0) / levels.length; console.log('=' .repeat(80)); console.log('📈 选择器类型分析:'); console.log(` 使用 ID 的: ${withId} 个 (${(withId/structure.elements.length*100).toFixed(1)}%)`); console.log(` 使用 Class 的: ${withClass} 个 (${(withClass/structure.elements.length*100).toFixed(1)}%)`); console.log(` 平均层级: ${avgLevels.toFixed(1)} 层`); console.log('=' .repeat(80) + '\n'); } // 4. 测试查找功能 console.log('🔍 测试查找"登录"按钮...\n'); const loginBtn = await test.callTool('find_element_by_text', { sessionId: sessionId, text: '登录' }); if (loginBtn && loginBtn.found) { console.log('✅ 找到登录按钮:'); console.log(` 文本: ${loginBtn.text}`); console.log(` 选择器: ${loginBtn.selector}`); console.log(` 长度: ${loginBtn.selector.length} 字符`); console.log(` 层级: ${loginBtn.selector.split('>').length} 层\n`); } // 5. 等待观察 console.log('⏳ 等待 3 秒后关闭...\n'); await new Promise(resolve => setTimeout(resolve, 3000)); // 6. 关闭会话 console.log('🔒 关闭会话...'); await test.callTool('close_session', { sessionId: sessionId }); console.log('✅ 测试完成!\n'); console.log('💡 优化说明:'); console.log(' - 优先使用元素 ID(最短)'); console.log(' - 查找最近的唯一祖先(减少层级)'); console.log(' - 限制最大层级为 5 层(避免过长)'); console.log(' - 保证选择器唯一性(精确匹配)\n'); } catch (error) { console.error('❌ 测试失败:', error.message); console.error(error.stack); } finally { await test.close(); } } console.log('🎯 开始选择器优化效果测试\n'); main().catch(error => { console.error('❌ 致命错误:', error); process.exit(1); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Leviathangk/PlaywrightMCPForCrawler'

If you have feedback or need assistance with the MCP directory API, please join our Discord server