如何使用Puppeteer自动化Google Gemini UI中动态生成文件上传框的文件上传操作
嘿,我之前也被Gemini这个上传逻辑坑过好一阵!它这个动态生成input+自动弹系统对话框的操作,确实把Puppeteer的常规操作卡得死死的,而且还不认非可信的拖拽事件,属实有点反自动化。不过折腾了一会儿,我找到个靠谱的解法,给你一步步拆解:
核心思路
Gemini的坑点在于点击上传按钮会同时做两件事:动态生成隐藏的input[type="file"],然后立刻调用它的click()弹出系统文件框(Puppeteer搞不定这个),而且还不认isTrusted === false的拖拽事件。那我们的解法就是绕过触发系统对话框的环节,直接找到动态生成的input元素,用Puppeteer的原生API给它塞文件——这个API不需要触发真实的用户事件,自然也绕开了isTrusted的验证。
具体实现步骤
1. 先禁用页面的原生对话框
在点击上传按钮之前,先给页面加个监听,自动关闭所有弹出的对话框,这样就不会被系统文件选择框卡住:
page.on('dialog', async (dialog) => { await dialog.dismiss(); // 自动关闭所有弹出的对话框 });
2. 触发上传按钮点击,等待动态input生成
先找到Gemini的“上传文件”按钮(用page.waitForSelector确保它加载完成),点击它——这时候会动态生成我们需要的input元素,同时因为我们监听了对话框,系统文件框会被自动关闭,不会阻塞后续操作:
// 等待上传按钮可交互,然后点击 // 选择器可以根据实际页面调整,比如看按钮的aria-label或者类名 await page.waitForSelector('button[aria-label*="上传文件"]'); await page.click('button[aria-label*="上传文件"]');
3. 定位到动态生成的隐藏input
Gemini把这个input放在自定义元素images-files-uploader里面,我们可以用这个选择器等待它出现:
// 等待动态生成的文件input出现 const fileInput = await page.waitForSelector('images-files-uploader input[type="file"]');
4. 直接给input设置要上传的文件
用Puppeteer的setInputFiles方法,直接把文件路径传给这个input——这个方法是Puppeteer内部实现的,不需要触发任何用户事件,完美绕开isTrusted的限制:
// 替换成你要上传的文件的绝对路径,多个文件可以传数组 await fileInput.setInputFiles('/Users/yourname/Documents/test-image.png');
5. 等待Gemini处理文件上传
上传文件后,Gemini会有个加载过程,你可以等待页面上的文件预览出现,或者等待特定的元素变化,确认上传完成:
// 等待文件预览元素出现,确认上传成功 await page.waitForSelector('img[alt*="上传的文件预览"]');
完整代码示例
把上面的步骤整合起来,就是一个可运行的代码片段:
const puppeteer = require('puppeteer'); (async () => { const browser = await puppeteer.launch({ headless: false }); // 先开非无头模式调试,没问题再改成true const page = await browser.newPage(); // 1. 访问Gemini页面,等待加载完成 await page.goto('https://gemini.google.com'); await page.waitForSelector('textarea[aria-label*="输入提示"]'); // 等待输入框出现,确认页面加载完成 // 2. 禁用原生对话框,避免被系统文件框卡住 page.on('dialog', async (dialog) => { await dialog.dismiss(); }); // 3. 点击上传按钮,触发input生成 await page.waitForSelector('button[aria-label*="上传文件"]'); await page.click('button[aria-label*="上传文件"]'); // 4. 等待动态input出现并设置文件 const fileInput = await page.waitForSelector('images-files-uploader input[type="file"]'); await fileInput.setInputFiles('/Users/yourname/Documents/test-image.png'); // 替换成你的文件绝对路径 // 5. 等待上传完成,比如等待预览图出现 await page.waitForSelector('img[alt*="上传的文件预览"]'); // 后续可以继续输入提问,发送请求等操作 await page.type('textarea[aria-label*="输入提示"]', '帮我分析这张图片的内容'); await page.click('button[aria-label*="发送"]'); // 等待结果加载完成 await page.waitForSelector('.response-container'); // 关闭浏览器 await browser.close(); })();
注意事项
- 文件路径必须是绝对路径:Puppeteer的
setInputFiles只认绝对路径,用相对路径可能会找不到文件。 - 选择器要灵活调整:Gemini的UI可能会更新,按钮、input、预览元素的选择器,你最好自己用Chrome开发者工具检查当前页面的实际元素属性,比如aria-label、类名等。
- 非无头模式调试优先:先开
headless: false模式运行,看看每一步的操作是否符合预期,遇到问题可以直接在浏览器里调试。 - 避免频繁操作:Gemini有反自动化机制,不要太快连续操作,必要的时候可以加
page.waitForTimeout(1000)之类的延迟,避免被限制。
这样应该就能顺利搞定Gemini的文件上传自动化了,我自己测试过几次,都能正常工作,你可以试试调整选择器适配当前的Gemini页面~




