C#使用Selenium操作WhatsApp网页版如何判断文件上传是否完成
解决方案
以下方案按稳定性从高到低排序,优先选择方案1:
方案1:通过JavaScript检测页面活跃上传请求(最稳定)
web.whatsapp的文件上传本质是走XMLHttpRequest或fetch发送POST请求到上传服务器,你可以通过Selenium注入JS脚本,统计当前活跃的上传类请求数,只要数值大于0就说明还在上传,完全不依赖不稳定的DOM选择器:
- 注入的JS脚本会拦截页面的XHR和fetch调用,标记上传相关的请求,你只需要定期调用JS获取当前活跃上传数即可
- C# 调用示例:
// 首次进入web.whatsapp页面时先注入监控脚本 ((IJavaScriptExecutor)driver).ExecuteScript(@" window.activeUploads = 0; // 拦截XHR请求 const originalOpen = XMLHttpRequest.prototype.open; XMLHttpRequest.prototype.open = function(method, url) { if (method === 'POST' && url.includes('mmg.whatsapp.net')) { window.activeUploads++; this.addEventListener('loadend', () => window.activeUploads--); this.addEventListener('error', () => window.activeUploads--); this.addEventListener('abort', () => window.activeUploads--); } return originalOpen.apply(this, arguments); }; // 拦截fetch请求 const originalFetch = window.fetch; window.fetch = function(resource, options) { const isUploadReq = (options?.method === 'POST' || method === 'POST') && resource.toString().includes('mmg.whatsapp.net'); if (isUploadReq) window.activeUploads++; return originalFetch.apply(this, arguments).finally(() => { if (isUploadReq) window.activeUploads--; }); }; "); // 每次上传文件后,轮询等待活跃上传数为0再跳转 while (true) { long activeUploads = (long)((IJavaScriptExecutor)driver).ExecuteScript("return window.activeUploads || 0;"); if (activeUploads == 0) break; Thread.Sleep(500); // 可根据实际需求调整轮询间隔 }
注:如果后续WhatsApp修改了上传域名,只要修改JS里的域名匹配关键词即可,不需要调整其他逻辑
方案2:通过通用DOM特征检测上传状态
不需要依赖固定选择器,只需要匹配页面内加载、进度相关的通用DOM特征判断上传状态:
// 轮询检测是否存在上传中相关的可见元素 while (true) { bool isUploading = (bool)((IJavaScriptExecutor)driver).ExecuteScript(@" const elements = document.querySelectorAll('*'); for (let el of elements) { const ariaLabel = el.getAttribute('aria-label') || ''; const className = el.className || ''; const role = el.getAttribute('role') || ''; // 匹配所有加载、上传、进度相关的特征 if ( ariaLabel.includes('上传') || ariaLabel.includes('loading') || ariaLabel.includes('progress') || className.includes('progress') || className.includes('upload') || className.includes('loader') || role === 'progressbar' ) { // 额外判断元素是否可见,排除隐藏的加载元素 return el.offsetParent !== null; } } return false; "); if (!isUploading) break; Thread.Sleep(500); }
方案3:等待上传预览元素生成
文件上传完成后,WhatsApp网页版会在输入框上方生成待发送的文件预览卡片,你可以等待该区域的预览元素稳定生成且无加载状态后再跳转:
// 定位输入框所在的父容器(该容器的特征相对稳定) var inputContainer = driver.FindElement(By.XPath("//div[@contenteditable='true']/ancestor::div[contains(@class, 'copyable-area')]")); // 轮询等待预览元素生成且无加载动画 while (true) { var previewElements = inputContainer.FindElements(By.XPath("./preceding-sibling::div//img | ./preceding-sibling::div//div[contains(@class, 'document')]")); if (previewElements.Count > 0) { // 确认预览元素没有关联的加载进度条 bool hasLoader = (bool)((IJavaScriptExecutor)driver).ExecuteScript("return arguments[0].querySelector('[role=\"progressbar\"]') !== null;", previewElements[0]); if (!hasLoader) break; } Thread.Sleep(500); }
内容的提问来源于stack exchange,提问作者MarkKoli
相关产品推荐
相关产品推荐

