如何使用Selenium Python录制Google会议并上传至服务器
解决Google Meet自动化录制问题
核心问题分析
你的代码存在几个关键问题导致录制无法启动:
- 仅定义了
startRecording异步函数,但从未调用执行 getDisplayMedia的权限授权在自动化环境下需要额外配置,默认会被浏览器拦截- 依赖
window.prompt会在无头/自动化环境下卡住流程 - 直接捕获麦克风音频无法正确获取Meet会议的共享音频(应该捕获标签页/桌面的音频流)
解决方案步骤
1. 添加必要的Chrome启动参数
为了自动授予媒体权限并跳过手动选择捕获源,更新ChromeOptions:
opt = uc.ChromeOptions() opt.add_argument('--disable-blink-features=AutomationControlled') opt.add_argument('--start-maximized') opt.add_argument('--disable-gpu') # 自动授予媒体流权限,跳过手动弹窗 opt.add_argument('--use-fake-ui-for-media-stream') # 指定捕获源为Google Meet标签页(桌面录制可改为"Entire screen") opt.add_argument('--auto-select-desktop-capture-source=Google Meet') # 用虚拟设备替代真实麦克风,避免权限问题 opt.add_argument('--use-fake-device-for-media-stream') opt.add_experimental_option("prefs", { "profile.default_content_setting_values.media_stream_mic": 1, "profile.default_content_setting_values.media_stream_camera": 1, "profile.default_content_setting_values.geolocation": 0, "profile.default_content_setting_values.notifications": 1, # 配置自动下载路径,关闭下载弹窗 "download.default_directory": "/path/to/your/download/folder", "download.prompt_for_download": False, "download.directory_upgrade": True })
2. 修改录制脚本,修复执行逻辑
- 调用
startRecording函数,处理异步执行 - 移除
window.prompt,使用时间戳命名文件避免冲突 - 优化音频捕获逻辑,优先捕获桌面/标签页的音频而非麦克风
recording_script = """ var blob, mediaRecorder = null; var chunks = []; async function startRecording(){ // 捕获屏幕+标签页音频,关闭音频降噪避免失真 let stream = await navigator.mediaDevices.getDisplayMedia({ video: {mediaSource: "screen"}, audio: { echoCancellation: false, noiseSuppression: false, autoGainControl: false } }); mediaRecorder = new MediaRecorder(stream, {mimeType: "video/webm"}); mediaRecorder.ondataavailable = (e) => { if(e.data.size > 0){ chunks.push(e.data); } }; mediaRecorder.onstop = () => { blob = new Blob(chunks, {type: "video/webm"}); chunks = []; var dataDownloadUrl = URL.createObjectURL(blob); // 自动下载到指定目录,无弹窗 let a = document.createElement('a'); a.href = dataDownloadUrl; a.download = `meet_recording_${Date.now()}.webm`; a.click(); URL.revokeObjectURL(dataDownloadUrl); }; mediaRecorder.start(250); } // 立即启动录制,捕获启动失败的错误 startRecording().catch(err => console.error("录制启动失败:", err)); """
3. 确保Meet账号有录制权限
Google Meet仅允许会议主持人或被授予录制权限的成员启动录制,所以你的机器人账号需要:
- 是会议创建者,或被主持人手动授予录制权限
- 使用Google Workspace账号(免费个人账号的录制功能有场景限制)
4. 处理录制文件上传到服务器
录制完成后,通过Python监听下载目录,找到最新录制文件并上传到服务器:
import os import requests # 配置下载目录和服务器上传地址 download_dir = "/path/to/your/download/folder" upload_url = "https://your-server.com/upload-endpoint" # 找到最新生成的webm录制文件 latest_file = max( [os.path.join(download_dir, f) for f in os.listdir(download_dir) if f.endswith('.webm')], key=os.path.getctime ) # 上传文件到服务器 with open(latest_file, 'rb') as f: response = requests.post(upload_url, files={'file': f}) if response.status_code == 200: print("文件上传成功") else: print(f"上传失败,状态码: {response.status_code}")
5. 完整修改后的代码
import undetected_chromedriver as uc from selenium.webdriver.common.by import By import time import os import requests recording_script = """ var blob, mediaRecorder = null; var chunks = []; async function startRecording(){ let stream = await navigator.mediaDevices.getDisplayMedia({ video: {mediaSource: "screen"}, audio: { echoCancellation: false, noiseSuppression: false, autoGainControl: false } }); mediaRecorder = new MediaRecorder(stream, {mimeType: "video/webm"}); mediaRecorder.ondataavailable = (e) => { if(e.data.size > 0){ chunks.push(e.data); } }; mediaRecorder.onstop = () => { blob = new Blob(chunks, {type: "video/webm"}); chunks = []; var dataDownloadUrl = URL.createObjectURL(blob); let a = document.createElement('a'); a.href = dataDownloadUrl; a.download = `meet_recording_${Date.now()}.webm`; a.click(); URL.revokeObjectURL(dataDownloadUrl); }; mediaRecorder.start(250); } startRecording().catch(err => console.error("录制启动失败:", err)); """ # 初始化下载目录 download_dir = "/path/to/your/download/folder" os.makedirs(download_dir, exist_ok=True) # 配置Chrome选项 opt = uc.ChromeOptions() opt.add_argument('--disable-blink-features=AutomationControlled') opt.add_argument('--start-maximized') opt.add_argument('--disable-gpu') opt.add_argument('--use-fake-ui-for-media-stream') opt.add_argument('--auto-select-desktop-capture-source=Google Meet') opt.add_argument('--use-fake-device-for-media-stream') opt.add_experimental_option("prefs", { "profile.default_content_setting_values.media_stream_mic": 1, "profile.default_content_setting_values.media_stream_camera": 1, "profile.default_content_setting_values.geolocation": 0, "profile.default_content_setting_values.notifications": 1, "download.default_directory": download_dir, "download.prompt_for_download": False, "download.directory_upgrade": True }) # 启动浏览器并加入会议 driver = uc.Chrome(options=opt) driver.get("meeting_url") driver.implicitly_wait(15) # 输入机器人名称 driver.find_element(By.XPATH,"/html/body/div/c-wiz/div/div/div[27]/div[3]/div/div[2]/div[4]/div/div/div[2]/div[1]/div[1]/div[3]/label/input").send_keys("test_bot") # 发送加入请求 driver.find_element(By.XPATH,"/html/body/div/c-wiz/div/div/div[27]/div[3]/div/div[2]/div[4]/div/div/div[2]/div[1]/div[2]/div[1]/div[1]/button").click() # 等待会议加载完成 time.sleep(10) # 执行录制脚本 driver.execute_script(recording_script) # 模拟录制时长(示例为30秒,可根据需求调整) time.sleep(30) # 停止录制 driver.execute_script("if(mediaRecorder) mediaRecorder.stop();") # 等待文件下载完成 time.sleep(5) # 上传文件到服务器 try: latest_file = max( [os.path.join(download_dir, f) for f in os.listdir(download_dir) if f.endswith('.webm')], key=os.path.getctime ) upload_url = "https://your-server.com/upload-endpoint" with open(latest_file, 'rb') as f: res = requests.post(upload_url, files={'file': f}) print(f"上传结果: {res.status_code} - {res.text}") except Exception as e: print(f"上传失败: {str(e)}") # 关闭浏览器 driver.quit()
额外注意事项
- XPATH定位器不稳定,Google Meet的DOM结构经常更新,建议改用
By.CSS_SELECTOR或基于aria-label等稳定属性定位元素 - 无头模式下屏幕捕获需要额外配置,建议先在有头模式下完成功能验证
- 长时间录制需考虑内存占用,可调整
MediaRecorder.start()的时间间隔参数,或增加chunk清理逻辑
内容的提问来源于stack exchange,提问作者Aninda
相关产品推荐
相关产品推荐

