MCP实战分享:使用Playwright MCP+Claude进行高效数据采集

如何选择最适合自己的MCP资源库?

面对这么多资源,如何选择最适合自己的呢?我根据实际经验给出以下建议:

根据技术水平选择:

  • 零基础用户:推荐Fleur(Mac用户)或mcp.run(Web用户)
  • 入门级开发者:Smithery.ai或Aimcp.info(中文用户)是理想选择
  • 专业开发者:MCP官方仓库和MCP-Toolkit提供更多技术深度

根据使用场景选择:

  • Cursor用户:首选Cursor Directory
  • VS Code用户:MCP Marketplace是最佳选择
  • 需要网页自动化:直接使用Playwright MCP Server
  • GitHub工作流优化:GitHub-MCP能大幅提升效率
  • 多模型测试需求:Glama MCP提供了理想的测试环境

根据特定需求选择:

  • 寻找最全面的资源:mcp.so目前收录量最大
  • 需要精选高质量工具:Awesome MCP Servers质量更有保障
  • 追踪最新动态:PulseMCP的周更新是了解前沿的窗口
  • 需要中文支持:Aimcp.info为中文用户提供便利

实战分享:使用Playwright MCP+Claude进行高效数据采集

在我的日常工作中,MCP已经成为提升效率的关键工具。以下是1个实际案例:使用Playwright MCP进行数据采集。

项目背景挑战

在一个市场分析项目中,我需要从15个不同的电商网站采集产品数据,包括:

  • 产品名称
  • 价格信息
  • 品牌
  • 规格参数
  • 用户评分
  • 库存状态

传统方法是手动访问每个网站,将数据复制到Excel表格,然后进行格式清洗和数据标准化,整个过程耗时约3天,且容易出错。如何提高效率成为了关键挑战。

解决方案概述

我采用的方案核心是将Playwright MCP作为Claude的"眼睛和手",实现对网页的自动化操作与数据提取。整体流程包括:

  1. 搭建Playwright MCP服务环境
  2. 在Claude中连接MCP服务
  3. 为Claude提供数据采集任务指南
  4. 利用Claude执行网页导航与数据提取
  5. 数据清洗与标准化处理
  6. 导出为标准格式

详细实施步骤

步骤1:配置Playwright MCP环境

首先,我们需要在本地安装并启动Playwright MCP服务:

# 安装Playwright MCP
npm install -g @playwright/mcp
# 启动MCP服务器
npx playwright-mcp start --port 8080

优化技巧:为了提高稳定性,特别是对付一些加载缓慢的电商网站,我使用了以下启动配置:

npx playwright-mcp start --port 8080 --timeout 120000 --headless=false

这将超时时间延长至120秒,并使用有头模式便于调试过程中观察浏览器行为。

步骤2:在Claude中连接MCP服务

根据使用的Claude客户端,连接方式略有不同:

Claude桌面应用:

  1. 打开Claude桌面应用
  2. 在右上角点击设置图标
  3. 选择"高级"选项卡
  4. 添加MCP配置:
    1. 名称: playwright
    2. URL: http://localhost:8080
  5. 点击连接按钮

Cursor编辑器:arduino

/mcp connect playwright http://localhost:8080

连接成功后,Claude会显示确认信息,表明它已经可以使用浏览器功能了。

步骤3:为Claude创建数据采集任务指南

与Claude交流的提示词设计至关重要。以下是我实际使用的任务指南模板:markdown

我需要从以下电商网站采集产品数据:
[网站URL列表]

对每个网站,请获取以下信息:
- 产品名称
- 价格
- 品牌
- 规格/尺寸
- 用户评分(如有)
- 库存状态

工作流程:
1. 访问网站并分析页面结构
2. 处理可能的弹窗(Cookie通知、登录提示等)
3. 定位产品列表元素
4. 提取每个产品的详细信息
5. 将数据整理为标准格式
6. 导出为CSV格式

请使用Playwright MCP执行这些任务,并实时报告进度。对于每个网站的特殊情况,我会提供额外指导。

步骤4:Claude执行数据采集

当Claude接收到任务后,它会使用Playwright MCP进行以下操作:

1.初始化浏览器并访问目标网站php

// 启动浏览器
const browser = await playwright.chromium.launch({
  headless: false,
  slowMo: 50 // 稍微放慢操作,避免被反爬
});
const context = await browser.newContext({
  userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
  viewport: { width: 1280, height: 800 },
  locale: 'en-US'
});
const page = await context.newPage();
await page.goto('https://example-ecommerce.com');

2.处理常见弹窗障碍

网站常见的Cookie提示、登录弹窗等会阻碍数据采集。Claude会自动处理这类情况:javascript

// 处理Cookie通知
try {
  const cookieSelectors = [
    'button:has-text("Accept")',
    'button:has-text("Accept All")',
    'button:has-text("同意")',
    '[id*="cookie"] button',
    '.cookie-banner button'
  ];

  for (const selector of cookieSelectors) {
    if (await page.$(selector)) {
      await page.click(selector);
      await page.waitForTimeout(1000);
      break;
    }
  }
} catch (e) {
  console.log("尝试处理Cookie通知,但没有找到匹配元素或出现错误");
}

3.分析页面结构并定位产品元素

Claude会分析页面DOM结构,找出最合适的选择器:ini

// 分析产品列表结构
const productContainers = [
  '.product-grid .product-item',
  '.products-list .item',
  '[data-testid="product-card"]',
  '.search-result-items .product-tile'
];
let productSelector;
for (const selector of productContainers) {
  const count = await page.$
$eval(selector, items => items.length);
  if (count > 0) {
    productSelector = selector;
    console.log(`找到产品列表: $
{selector},共${count}个商品`);
    break;
  }
}

4.提取产品数据

确定选择器后,Claude会提取每个产品的详细信息:dart

// 提取产品信息
const products = await page.$$eval(productSelector, items => {
  return items.map(item => {
    // 尝试多种可能的选择器组合以提高适应性
    const findText = (selectors) => {
      for (const selector of selectors) {
        const element = item.querySelector(selector);
        if (element && element.textContent.trim()) {
          return element.textContent.trim();
        }
      }
      return 'N/A';
    };

    return {
      name: findText(['.product-name', '.title', 'h2', 'h3']),
      price: findText(['.price', '.product-price', '[data-price]']),
      brand: findText(['.brand', '.product-brand', '[data-brand]']),
      specs: findText(['.specs', '.details', '.description']),
      rating: findText(['.rating', '.stars', '[data-rating]']),
      stock: findText(['.stock', '.availability', '.inventory'])
    };
  });
});

5.翻页处理

对于多页数据,Claude会实现翻页逻辑:ini

// 翻页逻辑
let hasNextPage = true;
let currentPage = 1;
const maxPages = 5; // 限制页数,避免过长时间运行
while (hasNextPage && currentPage < maxPages) {
  console.log(
正在处理第${currentPage}页
);

  // 提取当前页数据...

  // 检查是否有下一页
  const nextPageSelectors = [
    'a.next',
    '.pagination .next',
    'button:has-text("Next")',
    '[aria-label="Next page"]'
  ];

  let foundNextButton = false;
  for (const selector of nextPageSelectors) {
    const nextButton = await page.$(selector);
    if (nextButton) {
      foundNextButton = true;
      await nextButton.click();
      await page.waitForSelector(productSelector); // 等待新页面加载
      await page.waitForTimeout(2000); // 等待页面稳定
      break;
    }
  }

  if (!foundNextButton) {
    hasNextPage = false;
  }

  currentPage++;
}

步骤5:数据清洗与标准化

原始采集的数据通常需要进一步处理,Claude会执行以下数据清洗操作:ini

// 数据清洗与标准化
const processedProducts = products.map(product => {
  // 清理价格格式,提取数值
  const cleanPrice = product.price.replace(/[^\d.,]/g, '')
    .replace(/,/g, '.');
  const numericPrice = parseFloat(cleanPrice);

  // 规范化评分 (通常从文本转为1-5的数值)
  let normalizedRating = 'N/A';
  if (product.rating !== 'N/A') {
    const ratingMatch = product.rating.match(/(\d+(.\d+)?)/);
    if (ratingMatch) {
      normalizedRating = parseFloat(ratingMatch[1]);
      // 如果是10分制,转换为5分制
      if (normalizedRating > 5) {
        normalizedRating = (normalizedRating / 2).toFixed(1);
      }
    }
  }

  // 规范化库存状态
  let stockStatus;
  const stockText = product.stock.toLowerCase();
  if (stockText.includes('in stock') || stockText.includes('有货')) {
    stockStatus = '有货';
  } else if (stockText.includes('out of stock') || stockText.includes('无货')) {
    stockStatus = '无货';
  } else {
    stockStatus = '未知';
  }

  return {
    name: product.name,
    price: isNaN(numericPrice) ? product.price : numericPrice,
    brand: product.brand,
    specs: product.specs,
    rating: normalizedRating,
    stock: stockStatus
  };
});

步骤6:导出为CSV格式

最后,Claude会将处理好的数据导出为CSV格式:kotlin

// 转换为CSV
const createCSV = (data) => {
  if (!data || data.length === 0) return '';

  const headers = Object.keys(data[0]);
  const rows = [
    headers.join(','), // 表头行
    ...data.map(item =>
      headers.map(key => {
        // 处理包含逗号的文本,用引号包围
        const val = String(item[key] || '');
        return val.includes(',') ? 
"${val}"
 : val;
      }).join(',')
    )
  ];

  return rows.join('\n');
};
const csv = createCSV(processedProducts);
console.log(csv);

关键优化技巧

在实践中,我发现以下几个优化点能显著提高成功率:

1.模拟真实用户行为

网站的反爬机制越来越先进,模拟真实用户行为是关键:javascript

// 模拟真实用户行为
const simulateHumanBehavior = async (page) => {
  // 随机滚动
  await page.evaluate(() => {
    window.scrollBy({
      top: 100 + Math.random() * 400,
      behavior: 'smooth'
    });
  });

  // 随机暂停
  await page.waitForTimeout(1000 + Math.random() * 2000);

  // 偶尔悬停在某个元素上
  const randomElements = await page.$$('a, button, img');
  if (randomElements.length > 0) {
    const randomIndex = Math.floor(Math.random() * randomElements.length);
    await randomElements[randomIndex].hover();
  }
};
// 在页面操作中定期调用
await simulateHumanBehavior(page);

2.错误恢复与重试机制

网页采集经常会遇到临时性错误,加入重试机制很重要:javascript

// 带重试的元素操作
const clickWithRetry = async (page, selector, maxRetries = 3) => {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      await page.click(selector);
      return true;
    } catch (err) {
      console.log(
点击元素失败(尝试 ${attempt}/${maxRetries}): ${err.message}
);
      if (attempt === maxRetries) return false;
      await page.waitForTimeout(1000);
    }
  }
  return false;
};

3.并行处理多个网站

为了进一步提高效率,我实现了多个网站的并行处理:ini

// 并行处理多个网站(控制并发数)
const scrapeMultipleSites = async (urls, maxConcurrent = 3) => {
  const results = {};
  const chunks = [];

  // 将URL列表分成多个小批次
  for (let i = 0; i < urls.length; i += maxConcurrent) {
    chunks.push(urls.slice(i, i + maxConcurrent));
  }

  // 按批次并行处理
  for (const chunk of chunks) {
    console.log(
开始处理新的批次: ${chunk.join(', ')}
);

    const promises = chunk.map(url => scrapeWebsite(url));
    const batchResults = await Promise.all(promises);

    // 合并结果
    chunk.forEach((url, index) => {
      results[url] = batchResults[index];
    });
  }

  return results;
};

4.应对动态加载内容

现代电商网站大多使用动态加载,需要特别处理:ini

// 处理动态加载内容
const waitForDynamicContent = async (page, itemSelector, timeout = 10000) => {
  const startTime = Date.now();
  let prevCount = 0;

  while (Date.now() - startTime < timeout) {
    // 检查元素数量
    const currentCount = await page.$$eval(itemSelector, items => items.length);

    // 如果元素数量不再增加,说明加载完成
    if (currentCount > 0 && currentCount === prevCount) {
      console.log(
动态内容已加载完成,找到${currentCount}个元素
);
      return true;
    }

    prevCount = currentCount;

    // 滚动以触发加载
    await page.evaluate(() => {
      window.scrollBy(0, 500);
    });

    await page.waitForTimeout(500);
  }

  console.log(
等待动态内容超时,已找到${prevCount}个元素
);
  return prevCount > 0;
};

成果

通过实施这套方案,我们取得了显著成效:

  1. 时间效率: 从手动操作的3天缩短到自动化的4小时,效率提升约18倍
  2. 数据准确性: 错误率从25%降至2%,准确率提升了23%
  3. 数据完整性: 自动化采集能够处理更多数据点,提供了更全面的分析基础
  4. 可扩展性: 方案可轻松扩展到更多网站,只需微调适配各网站特性

Playwright MCP + Claude的组合极大地简化了网页数据采集工作,让AI成为数据处理的强大助手。这种方式不仅提高了效率,还降低了错误率,是企业数字化转型的理想工具。

随着MCP技术的不断发展,未来我们可以期待更多创新应用场景。例如,将这套系统与数据分析和可视化工具结合,实现从数据采集到分析报告的全流程自动化。

总结

MCP技术的出现,极大地拓展了AI大模型的能力边界,让Claude、Cursor等工具真正成为开发者的得力助手。这14个MCP资源库为不同需求的用户提供了丰富的工具选择,大大降低了使用门槛。