Browser-use工具自动化下载文件不稳定问题求助
Browser-use工具自动化下载文件不稳定问题求助
看起来你遇到的是browser-use结合Playwright做文件下载时的偶发性失败问题,从日志和代码来看,确实大概率和异步事件绑定的时机、并发处理有关,我帮你拆解下可能的问题点和对应的修复方案:
一、核心问题分析
从你的日志能看到,Agent已经完成了点击下载链接的操作,甚至标记任务成功,但实际没有文件被捕获——这说明你的下载事件监听可能没有及时绑定到正确的页面/上下文上,或者异步处理中出现了未被捕获的异常。
具体看你的代码,有几个潜在的风险点:
- 下载监听绑定时机太晚:你在
print_contexts_after_delay里延迟5秒才给context绑定page事件,而Agent可能在5秒内就已经完成了页面跳转和下载触发,这时候新页面创建时还没有监听download事件,自然捕获不到下载请求。 - 异步任务无错误处理:
handle_download是通过asyncio.create_task创建的,但没有做异常捕获,如果下载过程中出现报错(比如文件还没生成就尝试获取路径、权限问题),不会有任何日志,你根本不知道哪里出问题了。 - 页面监听范围不全:你只给第一个context绑定了
page事件,但如果browser-use创建了新的context,或者下载是在当前页面触发而非新页面,你的监听就覆盖不到。
二、具体修复方案
1. 提前绑定下载监听,不要延迟
把下载监听的绑定逻辑提前到浏览器初始化后,而不是等5秒。比如在main函数里拿到playwright_browser后直接绑定:
async def main(): task = "navigate to https://file-examples.com/index.php/sample-documents-download/sample-doc-download/ and download the first doc" model = ChatOpenAI(model='gpt-4o') agent = Agent( task=task, llm=model, controller=controller, browser=browser, ) # Get the underlying Playwright browser instance playwright_browser = await browser.get_playwright_browser() print('contexts initial:', len(playwright_browser.contexts)) # 👇 这里直接绑定,不要等5秒 # 给所有已存在的context绑定page事件 for context in playwright_browser.contexts: context.on("page", handle_page) # 给后续新建的context也绑定page事件 playwright_browser.on("context", lambda context: context.on("page", handle_page)) # 去掉原来的延迟任务 # asyncio.create_task(print_contexts_after_delay(playwright_browser)) await agent.run() # ... 后续代码不变
这样不管是初始context还是后续新建的,只要有新页面创建,都会立刻绑定下载监听,不会错过下载事件。
2. 给handle_download添加异常捕获+等待下载完成
在handle_download里加上try-except打印错误信息,同时显式等待下载完成,避免文件未生成就处理:
async def handle_download(download): try: # Create downloads directory if it doesn't exist downloads_dir = Path('./downloads') downloads_dir.mkdir(exist_ok=True) # 先等待下载完成,确保文件已生成 await download.wait_for_completion() # 获取下载文件路径 original_path = await download.path() if not original_path: print(f"下载失败:无法获取文件路径") return # Create new path in downloads directory new_path = downloads_dir / os.path.basename(original_path) # 检查原文件是否存在,避免移动失败 if not os.path.exists(original_path): print(f"下载失败:原文件不存在 {original_path}") return # Move the file to downloads directory os.rename(original_path, new_path) # Add the new path to downloaded files list downloaded_files.append(str(new_path)) print(f"Downloaded and moved to: {new_path}") except Exception as e: print(f"下载处理出错:{str(e)}")
3. 覆盖当前页面的下载监听
有些网站的下载是在当前页面触发(而非打开新页面),这时候需要给已存在的页面也绑定下载事件:
def handle_page(new_page): print("New page created!") new_page.on("download", lambda download: asyncio.create_task(handle_download(download))) async def main(): # ... 其他代码 playwright_browser = await browser.get_playwright_browser() # 给所有已存在的页面绑定下载监听 for context in playwright_browser.contexts: for page in context.pages: page.on("download", lambda download: asyncio.create_task(handle_download(download))) context.on("page", handle_page) playwright_browser.on("context", lambda context: context.on("page", handle_page)) # ... 后续代码
4. 增加下载确认步骤
可以给Agent加一个自定义动作,让它在点击下载后检查下载状态,确保文件生成再标记任务完成:
@controller.action('Check if download is completed', requires_browser=True) async def check_download(browser: BrowserContext): # 等待5秒给下载留时间 await asyncio.sleep(5) if downloaded_files: return f"下载完成,文件路径:{downloaded_files[-1]}" else: raise Exception("下载未完成,未捕获到文件")
然后修改任务描述,明确要求Agent执行点击后调用check_download动作。
三、测试建议
- 先把延迟绑定的逻辑去掉,换成提前全量绑定,这应该能解决大部分偶发的监听丢失问题。
- 运行时观察控制台的打印信息,如果有下载错误,根据捕获的异常进一步排查。
- 可以把
headless=False保持开启,手动观察下载触发时的页面行为,确认是新页面打开还是当前页面下载,再调整监听逻辑。
希望这些方案能帮你解决问题!
备注:内容来源于stack exchange,提问作者Benyamin Jafari
相关产品推荐
相关产品推荐

