你是不是也受够了自动化脚本里小红书登录这个老大难?每次验证码、滑块验证没完没了,登录状态还动不动就失效,搞得"全自动"最后总得人手来救场?
现在有了 Playwright 的 Model Context Protocol (MCP),这事儿就好办多了。它不再是简单地操控浏览器,而是能直接连上你已经登录的小红书会话。也就是说,你只需要手动登录一次,后面发笔记、互动这些操作,全都能放心交给脚本——再也不用跟登录验证死磕了。
想实现小红书图文自动发布却无从下手?这篇零基础教程将带你一步步搞定。我们将利用 Playwright MCP,实现真正的无人值守发布,内容全是纯干货。
一、环境准备与配置:打下坚实基础
1.1 安装 Playwright
确保你的 Python 环境在 3.7 以上,然后安装 Playwright:
pip install playwright playwright install chromium
1.2 安装配置 MCP 服务器
Playwright MCP 需要一个服务器来协调浏览器和你的自动化脚本:
# 通过 npm 全局安装 npm install -g @playwright/mcp # 或者使用 npx 直接运行 npx @playwright/mcp
1.3 安装浏览器扩展
这是实现会话复用的关键步骤:
- 下载 Playwright MCP Chrome 扩展(ZIP 文件)
- 打开 Chrome,进入
chrome://extensions/ - 开启“开发者模式”
- 点击“加载已解压的扩展程序”,选择解压后的文件夹
- 完成安装后,记得在扩展管理界面启用它
二、连接已登录的浏览器会话
2.1 启动浏览器并手动登录
首先,你需要让浏览器以调试模式运行:
# Windows chrome.exe --remote-debugging-port=9222 # macOS /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --remote-debugging-port=9222
然后在打开的浏览器中手动登录小红书账号,完成所有必要的验证步骤。
2.2 编写连接代码
创建一个 Python 文件,写入以下代码来连接已登录的浏览器:
import asyncio from playwright.async_api import async_playwright asyncdef connect_to_logged_in_browser(): asyncwith async_playwright() as p: # 连接到正在运行的浏览器实例 browser = await p.chromium.connect_over_cdp("http://localhost:9222") # 获取默认的浏览器上下文 default_context = browser.contexts[0] # 使用现有的页面或创建新页面 if default_context.pages: page = default_context.pages[0] else: page = await default_context.new_page() # 检查是否已登录 await page.goto('https://www.xiaohongshu.com') try: # 等待用户头像或其他登录后可见元素出现 await page.wait_for_selector('[data-testid="user-avatar"]', timeout=5000) print("✅ 检测到已登录状态") return page except: print("❌ 未检测到登录状态,请先手动登录") returnNone # 测试连接 asyncdef test_connection(): page = await connect_to_logged_in_browser() if page: await page.screenshot(path='login_status.png') print("截图已保存,请查看登录状态") await browser.disconnect() asyncio.run(test_connection())
三、完整的小红书图文发布脚本
以下是一个完整的自动化发布脚本,包含了异常处理和详细注释:
import asyncio from playwright.async_api import async_playwright import random import os class XiaohongshuAutoPublisher: def __init__(self): self.browser = None self.page = None asyncdef init_browser(self): """初始化浏览器连接""" try: playwright = await async_playwright().start() self.browser = await playwright.chromium.connect_over_cdp( "http://localhost:9222" ) self.context = self.browser.contexts[0] self.page = self.context.pages[0] if self.context.pages elseawait self.context.new_page() # 设置超时时间 self.page.set_default_timeout(30000) returnTrue except Exception as e: print(f"❌ 浏览器连接失败: {e}") returnFalse asyncdef goto_create_page(self): """导航到创作中心""" try: await self.page.goto('https://www.xiaohongshu.com/create', waitUntil='networkidle') # 等待发布界面加载完成 await self.page.wait_for_selector('div[contenteditable="true"]', timeout=15000) print("✅ 成功进入创作中心") returnTrue except Exception as e: print(f"❌ 进入创作中心失败: {e}") await self.page.screenshot(path='error_create_page.png') returnFalse asyncdef upload_images(self, image_paths): """上传图片""" try: # 等待文件上传输入框 await self.page.wait_for_selector('input[type="file"]', timeout=10000) # 获取文件上传句柄 file_input = await self.page.query_selector('input[type="file"]') if isinstance(image_paths, str): image_paths = [image_paths] await file_input.set_input_files(image_paths) print("✅ 图片上传成功") # 等待图片处理完成 await self.page.wait_for_selector('img[src*="upload"]', timeout=30000) await asyncio.sleep(2) # 额外等待确保完全加载 returnTrue except Exception as e: print(f"❌ 图片上传失败: {e}") await self.page.screenshot(path='error_upload.png') returnFalse asyncdef input_content(self, content, tags): """输入正文内容和标签""" try: # 定位正文编辑器 editor = await self.page.wait_for_selector('div[contenteditable="true"]', timeout=10000) # 清空现有内容 await editor.click(clickCount=3) # 三击全选 await self.page.keyboard.press('Backspace') # 输入内容 await editor.type(content) # 添加标签 if tags: tag_text = ' ' + ' '.join([f'#{tag}'for tag in tags]) await editor.type(tag_text) print("✅ 内容输入成功") # 添加随机延迟,模拟人类输入 await asyncio.sleep(random.uniform(1, 3)) returnTrue except Exception as e: print(f"❌ 内容输入失败: {e}") await self.page.screenshot(path='error_content.png') returnFalse asyncdef publish(self): """执行发布操作""" try: # 定位发布按钮 publish_button = await self.page.wait_for_selector('button:has-text("发布")', timeout=10000) await publish_button.click() print("✅ 已点击发布按钮") # 等待发布结果 try: await self.page.wait_for_selector('text=发布成功', timeout=15000) print("🎉 发布成功!") returnTrue except: # 检查是否有错误提示 error_element = await self.page.query_selector('text=/发布失败|错误/') if error_element: error_text = await error_element.inner_text() print(f"❌ 发布失败: {error_text}") else: print("⚠️ 发布状态未知,请手动确认") returnFalse except Exception as e: print(f"❌ 发布操作失败: {e}") await self.page.screenshot(path='error_publish.png') returnFalse asyncdef run(self, content, image_paths, tags=None): """执行完整发布流程""" ifnotawait self.init_browser(): returnFalse try: steps = [ (self.goto_create_page, "进入创作中心"), (lambda: self.upload_images(image_paths), "上传图片"), (lambda: self.input_content(content, tags), "输入内容"), (self.publish, "发布内容") ] for step_func, step_name in steps: print(f"▶️ 正在执行: {step_name}") ifnotawait step_func(): print(f"❌ 流程中断于: {step_name}") returnFalse # 步骤间随机延迟 await asyncio.sleep(random.uniform(1, 2)) returnTrue finally: if self.browser: await self.browser.disconnect() # 使用示例 asyncdef main(): publisher = XiaohongshuAutoPublisher() # 发布内容配置 content = """ Playwright MCP 真是太强大了!🤖 刚刚用全自动脚本发布了这篇小红书,完全不需要手动登录和验证。 #技术分享 #自动化 #Playwright #小红书运营 """ image_paths = [ '/path/to/your/image1.jpg', '/path/to/your/image2.jpg' ] tags = ['技术分享', '自动化', 'Playwright'] success = await publisher.run(content, image_paths, tags) if success: print("🎉 自动化发布流程完成!") else: print("❌ 发布流程失败") if __name__ == "__main__": asyncio.run(main())
四、高级技巧与最佳实践
4.1 会话保持与状态管理
# 保存浏览器状态,避免重复登录 asyncdef save_browser_state(): asyncwith async_playwright() as p: browser = await p.chromium.launch(headless=False) context = await browser.new_context() page = await context.new_page() # 手动登录过程... # 登录成功后保存状态 await context.storage_state(path='xiaohongshu_auth.json') await browser.close() # 使用保存的状态 asyncdef use_saved_state(): asyncwith async_playwright() as p: browser = await p.chromium.launch() context = await browser.new_context(storage_state='xiaohongshu_auth.json') page = await context.new_page() # 现在应该处于已登录状态
4.2 智能元素定位策略
# 使用多种选择器策略提高稳定性 asyncdef smart_click(text): selectors = [ f'button:has-text("{text}")', f'div:has-text("{text}")', f'//*[contains(text(), "{text}")]', f'[data-testid*="{text.lower()}"]' ] for selector in selectors: try: element = await self.page.wait_for_selector(selector, timeout=2000) await element.click() returnTrue except: continue print(f"❌ 找不到文本为 {text} 的元素") returnFalse
4.3 完整的错误处理与重试机制
async def robust_operation(operation, max_retries=3): """带重试机制的操作执行""" for attempt in range(max_retries): try: returnawait operation() except Exception as e: if attempt == max_retries - 1: raise e print(f"⚠️ 操作失败,第 {attempt + 1} 次重试: {e}") await asyncio.sleep(2 ** attempt) # 指数退避 # 使用示例 asyncdef safe_publish(): await robust_operation(lambda: self.page.click('button:has-text("发布")'))
五、常见问题与解决方案
5.1 连接被拒绝
问题:无法连接到 http://localhost:9222
解决方案:
- 确保浏览器以调试模式启动
- 检查防火墙设置,确保端口可访问
- 尝试使用不同的端口号
5.2 元素找不到或操作超时
问题:选择器失效或页面加载过慢
解决方案:
- 使用多种选择器策略组合
- 增加等待时间和重试机制
- 添加页面状态检查
5.3 风控检测
问题:操作被限制或账号被暂时封锁
解决方案:
- 添加随机延迟和人类化操作模式
- 避免高频次操作
- 使用多个账号轮换操作
六、总结
Playwright MCP 为小红书自动化发布带来了革命性的改进:
- 无需处理复杂登录:直接复用已登录的浏览器会话
- 更高的稳定性:避免了登录态失效和验证码问题
- 更接近真人操作:使用真实浏览器实例,降低被风控的风险
- 灵活的部署选项:既可以在本地运行,也可以部署到服务器
通过本教程,你已经掌握了使用 Playwright MCP 实现小红书全自动发布的完整流程。现在,你可以根据自己的需求扩展这个基础脚本,实现更复杂的自动化场景,如自动回复评论、数据分析、多账号管理等。
记住,技术是用来提高效率的工具,请在遵守平台规则的前提下合理使用自动化技术。祝你自动化之旅顺利!