You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 09:27:03