You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何使用Puppeteer自动化Google Gemini UI中动态生成文件上传框的文件上传操作

如何使用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页面~

火山引擎 最新活动