基于Playwright与MCP协议构建AI智能体实现自动化数据采集

发布时间:2026/7/17 21:48:15
基于Playwright与MCP协议构建AI智能体实现自动化数据采集 1. 项目概述当智能体学会“上网冲浪”最近在折腾一个挺有意思的项目让AI智能体自己去浏览器里“逛”自动完成数据采集任务。听起来是不是有点像科幻电影里的场景其实背后的核心就是Playwright和MCP这两个技术点的结合。简单来说Playwright是一个强大的浏览器自动化库而MCP则是一个让不同AI工具之间能“对话”的协议。把它们俩捏在一起就能打造出一个能理解你的自然语言指令然后像真人一样操作浏览器、抓取信息的“数字员工”。这个组合能解决什么问题呢想象一下你每天需要从几十个不同的网站上抓取价格、新闻、库存或者用户评论手动操作不仅耗时还容易出错。或者你需要监控某个竞品页面的动态变化一有更新就立刻知道。再或者你想把网页上的非结构化数据比如表格、列表自动整理成结构化的数据库。这些重复、繁琐的“脏活累活”正是自动化智能体的用武之地。它不眠不休不知疲倦只要规则设定好就能7x24小时稳定运行。这个项目适合谁呢如果你是一名数据分析师、产品运营、市场研究员或者任何需要频繁从网上获取数据的人那么这个方案能极大解放你的生产力。即使你之前没有太多编程经验只要对命令行和基础Python语法有所了解也能跟着一步步搭建起来。而对于开发者来说这更是一个探索AI Agent与真实世界Web交互的绝佳实践案例。2. 核心架构与工具选型解析2.1 为什么是Playwright不只是另一个Selenium在浏览器自动化领域Selenium是当之无愧的元老。但为什么在这个项目中我坚定地选择了Playwright这背后有几个关键的考量点。首先跨浏览器支持与一致性。Playwright由微软团队开发原生支持ChromiumChrome、Edge、Firefox和WebKitSafari三大浏览器引擎。它不像Selenium那样依赖各个浏览器厂商提供的驱动而是通过一套统一的API来控制浏览器这意味着在不同浏览器上的行为高度一致脚本的稳定性大大提升。对于数据采集来说我们有时需要模拟特定浏览器比如Safari来绕过一些反爬策略Playwright可以无缝切换。其次自动等待与可靠性。这是Playwright对比Selenium最显著的优点之一。Selenium脚本里充斥着大量的time.sleep()和显式等待代码既臃肿又脆弱。Playwright的API设计是“智能等待”的。例如当你执行page.click(‘button#submit’)时Playwright会自动等待这个按钮元素变得可交互可见、未被禁用、在视窗内才会去点击。这几乎消除了因页面加载或元素状态导致的随机失败让自动化脚本健壮得像石头一样。再者强大的网络拦截与模拟能力。Playwright可以轻松监听和修改网络请求。这对于数据采集至关重要。你可以拦截API请求直接拿到结构化的JSON数据这比从渲染后的HTML中解析要高效和准确得多。你也可以模拟慢速网络、离线状态或者注入自定义的请求头如User-Agent来更好地模拟真人行为或应对反爬。最后丰富的设备模拟与截图/录屏。Playwright可以模拟移动设备如iPhone 13的视口、User-Agent和触摸事件这对于采集移动端网页数据非常方便。其内置的截图和录屏功能不仅能用于调试还能在采集过程中自动保存关键页面的证据方便后续核对。注意虽然Playwright功能强大但其资源消耗尤其是内存通常比Selenium的纯驱动模式要高一些因为它启动的是一个完整的浏览器实例。在资源受限的服务器上运行时需要留意。2.2 MCP协议智能体的“通用翻译官”MCP全称是Model Context Protocol你可以把它理解成AI世界里的“USB协议”或“蓝牙协议”。它的核心目标是标准化AI应用如Claude Code、Cursor等与外部工具、数据源之间的通信方式。在没有MCP之前每个AI工具想要连接一个数据库、调用一个API或者操作一个本地软件都需要开发专属的、紧耦合的插件或适配器。这就像每个电器都需要一个特定形状的插座非常混乱。MCP协议定义了一套标准的“插头”和“插座”规范。在这个项目中MCP扮演的角色就是智能体与Playwright浏览器实例之间的桥梁。具体来说MCP Server服务器我们编写一个服务这个服务封装了所有Playwright的操作比如“打开网页”、“点击元素”、“获取文本”。这个服务遵循MCP协议对外暴露这些功能。MCP Client客户端我们的AI智能体运行在Claude Code、Cursor或自定义环境中就是一个MCP客户端。它通过MCP协议向Server发送标准化的请求例如{“tool”: “navigate”, “url”: “https://example.com”}。协议通信MCP通常使用JSON-RPC over stdio标准输入输出或WebSocket进行通信。这意味着智能体和Playwright控制器可以运行在两个完全独立的进程甚至机器上只要它们能通过MCP协议对话即可。这样做的好处是解耦和复用。你的智能体逻辑用什么模型、如何思考规划和浏览器操作逻辑如何点击、如何抓取被彻底分开了。今天你可以用Claude驱动这个Playwright MCP Server明天换用GPT或者DeepSeek完全不需要修改Server的代码。同样这个写好的Playwright MCP Server也可以被其他任何支持MCP的AI工具所使用。2.3 智能体框架的选择从“脚本”到“大脑”有了Playwright作为“手和脚”MCP作为“神经系统”我们还需要一个“大脑”来指挥整个行动。这就是智能体框架。这里有几个主流选择LangChain / LlamaIndex这是目前最流行的AI应用开发框架之一。它们提供了强大的工具调用Tool Calling、记忆Memory、智能体Agent工作流编排能力。你可以很方便地将我们的Playwright MCP Server封装成一个LangChain Tool然后由LangChain Agent来规划调用。优点是生态丰富文档齐全缺点是框架较重学习曲线稍陡。Semantic Kernel微软推出的框架与.NET生态结合紧密但同样支持Python。设计理念类似提供了规划器、插件等概念。自定义轻量级框架如果你追求极致的控制和简洁完全可以不用这些大框架。基于OpenAI或Anthropic的API利用其原生的“函数调用”Function Calling或“工具使用”Tool Use能力配合简单的循环和状态管理也能构建出功能强大的智能体。这对于理解底层原理非常有帮助。在这个项目中为了清晰展示从指令到行动的完整链条我倾向于从自定义轻量级方案开始。我们会用OpenAI的Chat Completions API利用其tools参数来定义我们的Playwright操作工具让模型学会在合适的时机调用这些工具。这样整个架构会非常透明用户指令 - AI模型思考 - 调用MCP工具 - Playwright执行 - 返回结果 - AI模型下一步思考...3. 环境搭建与核心组件实现3.1 基础环境与依赖安装首先我们需要一个干净的工作环境。强烈建议使用Python虚拟环境来管理依赖避免包冲突。# 1. 创建并进入项目目录 mkdir playwright-mcp-agent cd playwright-mcp-agent # 2. 创建Python虚拟环境这里使用venv你也可以用conda python -m venv venv # 3. 激活虚拟环境 # 在Windows上 venv\Scripts\activate # 在macOS/Linux上 source venv/bin/activate # 4. 安装核心依赖 pip install playwright openai # 安装Playwright所需的浏览器内核 playwright install chromium这里我们选择chromium作为默认浏览器因为它最轻量且兼容性最好。如果你需要Firefox或WebKit可以运行playwright install firefox webkit。3.2 构建Playwright MCP Server这是整个系统的“执行层”。我们将创建一个遵循MCP协议规范的服务器它持续监听输入解析JSON-RPC请求调用对应的Playwright操作并返回结果。首先我们定义Server能处理的工具Tools。一个基本的采集智能体至少需要以下能力navigate导航到一个新的URL。click点击页面上的某个元素通过CSS选择器或XPath。fill在输入框内填写文本。get_text获取某个元素的文本内容。screenshot对页面或某个区域截图。close_browser关闭浏览器释放资源。下面是一个高度简化的MCP Server实现框架展示了核心逻辑# mcp_server.py import json import sys from typing import Any, Dict from playwright.sync_api import sync_playwright, Page class PlaywrightMCPServer: def __init__(self): self.playwright None self.browser None self.page: Page None self._init_browser() def _init_browser(self): 初始化浏览器实例。建议使用非无头模式进行调试。 self.playwright sync_playwright().start() # headlessFalse 表示打开可见的浏览器窗口便于调试 self.browser self.playwright.chromium.launch(headlessFalse, slow_mo100) # slow_mo让动作变慢方便观察 self.page self.browser.new_page() print(Playwright浏览器已启动。, filesys.stderr) def handle_request(self, request: Dict[str, Any]) - Dict[str, Any]: 处理单个JSON-RPC请求。 method request.get(method) params request.get(params, {}) request_id request.get(id) result None error None try: if method navigate: url params[url] self.page.goto(url, wait_untilnetworkidle) # 等待网络空闲 result {status: success, url: self.page.url} elif method click: selector params[selector] self.page.click(selector) result {status: success} elif method fill: selector params[selector] text params[text] self.page.fill(selector, text) result {status: success} elif method get_text: selector params[selector] text_content self.page.text_content(selector) result {text: text_content} elif method screenshot: path params.get(path, screenshot.png) self.page.screenshot(pathpath, full_pageTrue) result {path: path} elif method close_browser: self.browser.close() self.playwright.stop() result {status: closed} else: error {code: -32601, message: fMethod not found: {method}} except Exception as e: error {code: -32000, message: str(e)} response { jsonrpc: 2.0, id: request_id } if error: response[error] error else: response[result] result return response def run(self): 主循环从stdin读取请求向stdout写入响应。 print(Playwright MCP Server 正在运行..., filesys.stderr) while True: line sys.stdin.readline() if not line: break try: request json.loads(line.strip()) response self.handle_request(request) sys.stdout.write(json.dumps(response) \n) sys.stdout.flush() except json.JSONDecodeError: error_resp json.dumps({ jsonrpc: 2.0, id: None, error: {code: -32700, message: Parse error} }) sys.stdout.write(error_resp \n) sys.stdout.flush() if __name__ __main__: server PlaywrightMCPServer() server.run()这个Server通过标准输入输出stdio与外界通信这是MCP Server一种常见的实现方式。AI客户端比如我们的智能体会启动这个Python进程并通过管道向其发送JSON-RPC格式的指令。3.3 集成AI智能体客户端现在我们来构建“大脑”。我们将使用OpenAI的Chat Completions API并利用其tools参数来定义我们刚刚创建的Playwright工具。# agent_client.py import json import subprocess import threading import time from openai import OpenAI class PlaywrightAgent: def __init__(self, api_key: str, model: str gpt-4o): self.client OpenAI(api_keyapi_key) self.model model # 启动MCP Server子进程 self.server_process subprocess.Popen( [python, mcp_server.py], stdinsubprocess.PIPE, stdoutsubprocess.PIPE, stderrsubprocess.PIPE, textTrue, bufsize1 ) # 启动一个线程来读取Server的输出主要是错误信息 threading.Thread(targetself._read_stderr, daemonTrue).start() time.sleep(2) # 等待Server启动 print(智能体与MCP Server连接就绪。) def _read_stderr(self): 读取Server进程的stderr用于调试。 while True: line self.server_process.stderr.readline() if line: print(f[MCP Server STDERR] {line}, end) def _call_mcp_tool(self, tool_name: str, **kwargs) - dict: 向MCP Server发送一个工具调用请求。 request { jsonrpc: 2.0, id: 1, method: tool_name, params: kwargs } request_str json.dumps(request) \n self.server_process.stdin.write(request_str) self.server_process.stdin.flush() # 读取响应 response_line self.server_process.stdout.readline() try: response json.loads(response_line.strip()) if error in response: print(f工具调用错误: {response[error]}) return {error: response[error][message]} return response.get(result, {}) except json.JSONDecodeError: return {error: Failed to parse server response} def run(self, user_query: str): 执行用户查询的主循环。 messages [{role: user, content: user_query}] # 定义可用的工具必须与MCP Server提供的匹配 tools [ { type: function, function: { name: navigate, description: 导航到一个新的网页URL。, parameters: { type: object, properties: { url: {type: string, description: 要访问的完整URL。} }, required: [url] } } }, { type: function, function: { name: get_text, description: 获取网页上指定CSS选择器元素的文本内容。, parameters: { type: object, properties: { selector: {type: string, description: CSS选择器如‘h1.title’或‘div#content’。} }, required: [selector] } } }, # ... 同样定义 click, fill, screenshot, close_browser 等工具 ] max_steps 10 # 防止无限循环 for step in range(max_steps): print(f\n--- 智能体思考步骤 {step1} ---) # 调用OpenAI API传入当前对话历史和工具定义 response self.client.chat.completions.create( modelself.model, messagesmessages, toolstools, tool_choiceauto, # 让模型决定是否调用工具 ) response_message response.choices[0].message messages.append(response_message) # 将AI的回复加入历史 # 检查AI是否决定调用工具 tool_calls response_message.tool_calls if tool_calls: for tool_call in tool_calls: function_name tool_call.function.name function_args json.loads(tool_call.function.arguments) print(f智能体决定调用工具: {function_name} 参数: {function_args}) # 执行工具调用 result self._call_mcp_tool(function_name, **function_args) print(f工具执行结果: {result}) # 将工具调用结果作为一条新消息加入历史供AI进行下一步推理 messages.append({ role: tool, tool_call_id: tool_call.id, content: json.dumps(result), }) else: # AI没有调用工具直接给出了最终答案 print(f智能体最终回复: {response_message.content}) break else: print(达到最大步骤限制任务可能未完成。) # 任务结束后关闭浏览器 self._call_mcp_tool(close_browser) self.server_process.terminate() print(任务结束资源已清理。) if __name__ __main__: # 请替换为你的OpenAI API Key AGENT PlaywrightAgent(api_keyyour-openai-api-key-here) AGENT.run(请打开百度首页搜索‘今日天气’然后告诉我第一个搜索结果标题。)这个智能体会将用户的自然语言指令如“搜索今日天气”分解为一系列具体的工具调用navigate-fill-click-get_text并通过MCP协议驱动Playwright执行。4. 实战构建一个商品价格监控智能体让我们用一个更贴近实际的例子把上面的组件串联起来。假设我们要监控某个电商网站例如一个书籍网站上特定商品的价格变化。4.1 任务分析与规划目标每天自动检查《深入理解计算机系统》这本书在该网站上的价格如果价格低于100元就记录一条信息。分解步骤导航到商品页面。定位价格元素并获取文本。解析文本提取数字价格。判断价格是否低于阈值。记录结果打印或存入文件/数据库。这里的关键在于如何让AI智能体稳定地找到价格元素。网站结构可能会变纯靠CSS选择器很脆弱。更好的策略是结合多种定位方式并让AI具备一定的“容错”和“探索”能力。4.2 增强MCP Server更鲁棒的元素定位我们需要升级MCP Server中的get_text工具使其更智能。例如我们可以提供一个get_element_with_fallback工具它尝试多种选择器直到找到一个为止。# 在PlaywrightMCPServer类中添加新工具方法 def handle_request(self, request): # ... 之前的其他工具判断 ... elif method get_element_text_with_fallback: selectors params[selectors] # 传入一个选择器列表 text None used_selector None for selector in selectors: if self.page.locator(selector).count() 0: text self.page.text_content(selector) used_selector selector break if text: result {text: text, selector_used: used_selector} else: result {text: None, error: No matching element found with any selector} # ...同时我们还需要一个工具来获取当前页面的结构化信息帮助AI了解页面布局做出更好决策。例如get_page_summary工具可以返回页面标题、所有H1标签、以及可能包含价格的常见元素如带有‘’ ‘$’ ‘price’类名的元素。elif method get_page_summary: title self.page.title() h1_list [self.page.text_content(fh1:nth-of-type({i})) for i in range(1, 6) if self.page.locator(fh1:nth-of-type({i})).count()0] # 寻找可能的价格元素 price_candidates [] for selector in [.price, .current-price, [itempropprice], span:has-text(), span:has-text($)]: elements self.page.locator(selector).all() for idx, element in enumerate(elements[:5]): # 取前5个 price_candidates.append({ selector: selector, index: idx, text: element.text_content()[:50] # 取前50字符 }) result { title: title, h1_headings: h1_list, price_candidates: price_candidates }4.3 编写智能体任务指令与运行现在我们可以给智能体一个更高级的指令让它利用这些增强的工具。# 在agent_client.py的tools列表中新增我们定义的工具 tools.append( { type: function, function: { name: get_element_text_with_fallback, description: 尝试用多个CSS选择器获取元素文本直到成功为止。, parameters: { type: object, properties: { selectors: { type: array, items: {type: string}, description: CSS选择器数组按顺序尝试。 } }, required: [selectors] } } } ) tools.append( { type: function, function: { name: get_page_summary, description: 获取当前页面的摘要信息包括标题、主要标题和可能的价格元素。用于了解页面结构。, parameters: {type: object, properties: {}} } } ) # 运行一个复杂的任务 agent.run( 请访问‘https://example-bookstore.com/product/12345’这个网址。 你的任务是找出这本书的当前售价。 首先获取页面摘要了解结构。 然后尝试用以下选择器来定位价格元素[.product-price, .current-price span, [data-testidprice], span:has-text()]。 从找到的价格文本中提取出纯数字价格例如从‘89.50’中提取89.5。 如果价格低于100请告诉我‘价格低于100元当前价为X元’。否则告诉我‘价格是X元未低于阈值’。 请一步步进行。 )智能体会自主执行导航 - 获取摘要 - 分析摘要 - 尝试多种选择器获取价格文本 - 解析文本 - 判断并输出结果。这个过程完全自动化无需人工干预编写针对该页面的特定抓取规则。5. 高级技巧与避坑指南在实际操作中你会遇到各种预料之外的问题。下面是我在多次实践中总结出的核心经验和避坑点。5.1 对抗反爬策略如何更像“人”直接使用Playwright自动化脚本很容易被网站识别并屏蔽。以下是几种有效的伪装策略随机化等待与操作在关键操作点击、翻页之间加入随机延迟模拟人类思考时间。不要使用固定的sleep。import random, time time.sleep(random.uniform(1.0, 3.0)) # 等待1到3秒之间的随机时间使用真实User-Agent与视口避免使用默认的Headless Chrome UA。可以轮换一批常见的桌面和移动端UA。user_agents [ Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 ..., Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 ..., ] context browser.new_context(user_agentrandom.choice(user_agents), viewport{width: 1920, height: 1080}) page context.new_page()启用浏览器上下文与Cookie持久化创建一个浏览器上下文browser.new_context()并定期保存和加载Cookiecontext.storage_state(path”state.json”)可以让会话看起来更持久、更真实。谨慎使用无头模式对于反爬极强的网站可以考虑使用非无头模式headlessFalse甚至配合一些浏览器指纹隐藏插件但Playwright对此支持有限。不过这会在服务器上打开GUI需要运行在带有显示器的环境或使用虚拟显示如Xvfb。重要提示所有自动化数据采集行为都必须遵守网站的robots.txt协议和相关服务条款。对于个人学习和小规模、低频率的采集上述技巧通常足够。但对于商业用途或大规模采集务必寻求合法合规的解决方案如使用官方API。5.2 错误处理与脚本健壮性自动化脚本最怕不稳定。必须建立完善的错误处理和重试机制。元素定位失败这是最常见的问题。不要只用一个选择器。使用page.locator(selector).wait_for(state”attached”, timeout10000)等待元素出现或者像我们之前那样实现fallback机制。对于动态加载的内容要监听网络请求或使用page.wait_for_function。网络异常与页面崩溃在page.goto和关键操作外包裹try-except捕获TimeoutError或TargetClosedError。实现指数退避重试逻辑。import asyncio from playwright.async_api import TimeoutError as PlaywrightTimeoutError async def robust_goto(page, url, retries3): for attempt in range(retries): try: await page.goto(url, wait_untilnetworkidle, timeout30000) return True except PlaywrightTimeoutError: print(f导航超时第{attempt1}次重试...) await asyncio.sleep(2 ** attempt) # 指数退避 print(f导航失败: {url}) return False结果验证工具调用后不要完全相信AI对结果的解析。在关键步骤如获取价格后加入验证逻辑。例如检查获取的文本是否包含数字价格是否在一个合理范围内等。5.3 性能优化与资源管理当需要监控大量页面时性能成为关键。复用浏览器实例避免为每个任务都启动和关闭浏览器。我们的MCP Server设计就是长期运行一个浏览器实例处理多个连续任务。但要注意内存泄漏定期检查并清理无用的页面page.close()。并行处理Playwright支持异步APIplaywright.async_api。你可以创建多个浏览器上下文Context甚至多个页面Page在一个浏览器实例内并行运行任务。每个上下文拥有独立的Cookie和缓存相互隔离。async with async_playwright() as p: browser await p.chromium.launch() # 创建多个上下文并行工作 tasks [scrape_task(browser, url) for url in url_list] await asyncio.gather(*tasks)控制超时与资源为page.goto、page.wait_for_selector等操作设置合理的超时时间。对于永不加载完成的页面如含有错误JS要有兜底超时并终止任务。5.4 智能体提示工程AI智能体的表现很大程度上取决于你给它的“工具描述”和“系统提示词”。工具描述要精确在定义tools时description和parameters的描述要清晰、无歧义。例如selector参数要说明是CSS选择器并举例说明。好的描述能极大减少AI的错误调用。系统提示词设定角色与规则在对话开始时可以通过messages参数插入一条role为system的消息来设定AI的行为准则。system_prompt 你是一个专业的网页数据采集助手。你通过调用工具来操作浏览器。 规则 1. 在操作前先观察页面结构使用get_page_summary。 2. 定位元素时优先使用最具体的选择器如果失败再尝试更通用的或备选方案。 3. 每次操作后确认结果是否符合预期。 4. 如果遇到错误如元素未找到不要放弃尝试分析页面摘要寻找其他可能的选择器或方法。 5. 最终答案应简洁、准确包含核心数据。 messages [{role: system, content: system_prompt}, {role: user, content: user_query}]让AI学会“思考”在复杂任务中鼓励AI将大任务分解为多个子步骤并在调用工具前先输出它的“思考”过程可以通过在messages中让AI以特定格式输出。这虽然会增加Token消耗但能显著提升任务成功率也便于调试。6. 常见问题与故障排查实录即使准备再充分实际运行中还是会遇到各种问题。下面是一个快速排查清单涵盖了90%的常见情况。问题现象可能原因排查步骤与解决方案MCP Server启动失败或立即退出1. Python路径或依赖错误。2. Playwright浏览器未安装。1. 在终端激活虚拟环境后手动运行python mcp_server.py查看具体的错误输出。2. 运行playwright install chromium确保浏览器已安装。智能体无法连接MCP Server无响应1. 子进程管道通信阻塞。2. Server端JSON解析错误导致崩溃。1. 检查subprocess.Popen的参数确保stdin,stdout设置为subprocess.PIPE并启用textTrue和bufsize1行缓冲。2. 在Server端代码中加入更详细的异常捕获和日志打印确保任何错误都不会导致进程静默退出。AI模型不调用工具一直说“作为AI我无法...”1. 工具描述tools参数未正确传递给API。2. 系统提示词限制了AI的行为。3. 模型版本不支持工具调用如使用了非Chat模型。1. 打印检查发送给OpenAI API的tools列表格式是否正确。2. 修改系统提示词明确告知AI“你必须使用我提供的工具来完成操作”。3. 确保使用支持工具调用的模型如gpt-4o,gpt-4-turbo,gpt-3.5-turbo等。Playwright操作超时TimeoutError1. 网络慢或页面加载失败。2. 元素选择器错误元素一直不出现。3. 页面有弹窗、验证码拦截。1. 增加page.goto的timeout参数或使用wait_until”domcontentloaded”而非”networkidle”。2. 打开headlessFalse模式肉眼观察页面是否正常加载元素是否存在。使用浏览器开发者工具验证选择器。3. 脚本中增加处理常见弹窗的代码如page.on(“dialog”, lambda dialog: dialog.accept())。对于验证码自动化方案有限可能需要人工干预或使用第三方打码服务。获取到的文本是空或乱码1. 元素内容是动态加载的获取时还未渲染。2. 元素内有嵌套结构text_content()获取不全。3. 页面编码问题。1. 在get_text操作前先使用page.wait_for_selector(selector, state”attached”)等待。2. 尝试使用page.inner_text(selector)或page.locator(selector).inner_html()获取不同格式的内容。3. 检查Playwright启动的浏览器语言和编码设置。脚本运行几次后速度变慢或内存飙升1. 页面对象未关闭导致内存泄漏。2. 浏览器缓存累积。1. 确保每个任务完成后关闭不再需要的page对象page.close()。在长期运行的Server中考虑定期重启浏览器实例。2. 创建浏览器上下文时可以传入no_viewportTrue,ignore_https_errorsTrue等选项减少负载或定期清理缓存。一个真实的踩坑记录在一次监控任务中智能体总是无法在某个电商网站找到“加入购物车”按钮。通过headlessFalse模式观察发现该按钮在页面滚动到一定位置时才变为可见并启用。Playwright的默认点击会滚动到元素位置但可能滚动后元素状态变化需要时间。解决方案是在点击前先使用page.evaluate执行一段JavaScript将元素滚动到视窗中央然后page.wait_for_function等待按钮的disabled属性变为false最后再点击。这个案例说明最可靠的自动化往往需要模拟最真实的人为操作节奏和状态判断。构建基于Playwright和MCP的智能体是一个将“感知AI”、“决策模型”、“执行浏览器”闭环的过程。从简单的页面导航到复杂的多步骤数据提取这个框架提供了极高的灵活性和可扩展性。最大的挑战往往不在于技术实现而在于如何设计鲁棒的任务流程、编写精准的提示词以及处理真实Web环境中的各种不确定性。