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

Selenium无input标签文件上传及保存样式重置问题

Selenium 自动化操作 trovo.live 修改用户头像问题方案

问题梳理

  • 点击页面「Upload」按钮会直接唤起系统文件选择弹窗,通过document.getElementsByTagName("input")全量遍历DOM,无法找到对应file类型的<input>元素,无法使用常规element.SendKeys()方式传入本地文件路径完成上传。
  • 站点逻辑分析:手动选择文件后,站点会自动将选中图片转换为data URI格式,赋值给头像预览<img>标签的src属性,同时设置style属性中的transform: matrix()参数,完成图片裁剪、缩放、定位调整全流程。
  • 手动模拟逻辑失效:自行将目标图片转为data URI赋值给预览img的src属性,同时手动计算matrix参数设置对应transform样式后,点击保存按钮站点会重置手动设置的CSS样式,最终保存的头像定位错误;通过Upload按钮手动上传时设置的matrix参数可被正常识别保存。

现有约束

  • HTML静态源码中不存在承载文件上传功能的<input>标签
  • 无法使用System.Windows.Forms.SendKeys.SendWait()方法向系统弹窗传入文件路径
  • 引入AutoItX等第三方库处理弹窗存在项目兼容问题,优先要求不依赖第三方库实现
  • 已定位到站点实现上传功能的JS源码,但不清楚如何直接调用内部图片缩放、上传相关方法

对应解决方案

1. 介入保存按钮执行逻辑,强制传入自定义matrix参数

保存时手动设置的CSS被重置,核心原因是站点仅认自身上传流程中写入内存的裁剪状态参数,不会读取DOM上手动修改的style值。
通过Selenium的execute_script能力即可实现参数注入:

  • 先在浏览器控制台打断点调试,找到保存逻辑中读取裁剪参数的内部状态变量,通常挂载在window全局对象或组件实例上,例如window.__avatarCropper.config这类路径
  • 点击保存按钮前,通过JS直接修改对应内部状态变量,把提前计算好的6个matrix参数赋值进去,再触发原保存逻辑,站点不会识别到参数被篡改,也不会重置样式
  • 核心代码示例:
// 实际变量路径需通过断点调试确认,此处为示例
window.__trovoAvatarModule.cropConfig.matrix = [scaleX, skewY, skewX, scaleY, translateX, translateY];
// 触发原生保存逻辑
document.querySelector('.avatar-save-submit').click();

2. 绕过按钮点击,直接模拟站点上传函数逻辑

既然已经定位到站点上传相关的JS源码,完全不需要触发文件选择弹窗,直接构造参数调用内部上传方法即可:

  • 在源码中定位到文件选择完成后的回调函数,这类方法通常接收File/Blob对象作为入参,负责后续的图片解析、裁剪初始化、预览渲染流程
  • 通过Selenium执行JS,先将目标图片转为对应格式的Blob对象(可先读取本地图片为base64,再转换为Blob,注意MIME类型需和图片实际格式匹配)
  • 将构造好的Blob对象作为入参,直接调用定位到的内部上传回调方法,后续站点会自动走完原生的裁剪、预览、保存流程,不需要手动修改DOM样式
  • 如果目标方法在闭包内未暴露到window全局,可通过劫持事件监听、断点拦截的方式拿到方法引用,挂载到window上后再调用。

3. 无第三方依赖,通过Selenium原生能力处理文件选择弹窗

找不到file类型input通常是两种原因:一是input是点击Upload按钮时动态创建的,触发文件选择后立刻从DOM移除,常规遍历时机不对抓不到;二是input被放置在shadow DOM内部,普通DOM遍历方法无法穿透查找,两种情况都可以用Selenium原生能力解决:

  • 针对动态创建input的场景:点击Upload按钮前,先通过JS重写document.createElement方法,监听type为file的input创建时机,将元素缓存到window自定义变量上,同时拦截input的click事件阻止系统弹窗唤起。点击Upload按钮后,直接从缓存变量拿到file input元素,用Selenium原生的sendKeys传入本地文件绝对路径即可,不需要处理系统弹窗。
    核心拦截代码示例:
    window._cachedFileInput = null;
    const originCreate = document.createElement.bind(document);
    const typeProp = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'type');
    document.createElement = function(tag) {
      const el = originCreate(tag);
      if (tag.toLowerCase() === 'input') {
        typeProp.set.call(el, 'file');
        Object.defineProperty(el, 'type', {
          set: function(val) {
            if (val === 'file') window._cachedFileInput = el;
            return typeProp.set.call(this, val);
          },
          get: () => typeProp.get.call(el)
        });
        el.addEventListener('click', e => {
          e.stopImmediatePropagation();
          e.preventDefault();
        }, true);
      }
      return el;
    }
    
  • 针对shadow DOM场景:递归遍历页面所有元素的shadowRoot节点,在每个shadowRoot内部查找type为file的input元素,找到后直接调用sendKeys传入文件路径即可,无需唤起系统弹窗。

内容的提问来源于stack exchange,提问作者SPIRINN

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 03:06:22