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

能否为JavaScript的FileList写原型构造File对象?适配路由器固件更新自动化

解决路由器固件更新自动化中的FileList构造问题

嘿,这个场景我刚好折腾过,咱们直接说结论:完全可以通过构造符合标准的FileList对象(甚至扩展它的原型)来绕过这个JS处理的限制,结合Selenium的JS注入能力就能搞定。下面一步步给你讲具体怎么做:

核心思路

路由器的onsubmit JS会依赖FileList来获取上传的固件文件,而原生FileList是只读的,不能直接修改。但我们可以通过Selenium的execute_script()方法注入自定义JS,手动构造包含目标File对象的FileList,再替换到文件输入框的files属性上,这样JS处理逻辑就会认为是正常上传的文件了。

具体实现步骤

1. 准备固件文件并传入JS

先把本地的固件文件读成二进制数据,然后通过Selenium的execute_script()参数传递给JS代码:

from selenium import webdriver

# 初始化PhantomJS(如果兼容性有问题,建议换成Headless Chrome)
driver = webdriver.PhantomJS()
driver.get("你的路由器固件更新页面URL")

# 读取本地固件文件
with open("firmware.bin", "rb") as f:
    firmware_bytes = f.read()

2. 注入JS构造FileList并替换

这一步是关键,我们要在浏览器环境里创建Blob、File对象,再构造一个符合FileList接口的对象:

# 执行自定义JS
driver.execute_script("""
    // 把Python传入的二进制数据转成Blob(模拟文件内容)
    const firmwareBlob = new Blob([arguments[0]], { type: 'application/octet-stream' });
    // 创建File对象,文件名和MIME类型要和路由器表单要求一致!
    const firmwareFile = new File([firmwareBlob], 'firmware.bin', { type: 'application/octet-stream' });
    
    // 构造FileList对象:因为原生FileList不能直接修改,我们基于它的原型创建
    const customFileList = Object.create(FileList.prototype);
    // 添加File对象到索引0的位置
    Object.defineProperty(customFileList, '0', { value: firmwareFile });
    // 设置FileList的长度为1
    Object.defineProperty(customFileList, 'length', { value: 1 });
    
    // 找到页面上的文件输入框,替换它的files属性
    const fileInput = document.querySelector('input[type="file"]');
    Object.defineProperty(fileInput, 'files', { value: customFileList });
""", firmware_bytes)

3. 触发表单提交并通过校验

现在文件输入框的files已经是我们构造的FileList了,直接触发提交操作即可:

# 点击提交按钮(或者直接调用表单的submit()方法)
submit_btn = driver.find_element_by_css_selector('button[type="submit"]')
submit_btn.click()

关键注意事项

  • PhantomJS兼容性问题:PhantomJS已经停止维护,对ES6的支持有限,如果遇到File构造函数报错,可以换成Blob代替(有些旧JS逻辑会兼容Blob),或者直接换成Headless Chrome,稳定性和兼容性会好很多。
  • 表单校验匹配:路由器的JS校验会检查文件名、文件类型甚至文件大小,你要确保构造的File对象的文件名、MIME类型和正常手动上传的完全一致,不然会触发校验失败。
  • onsubmit事件触发:尽量模拟用户点击提交按钮,而不是直接调用form.submit(),这样能确保onsubmit事件被正常触发,JS处理逻辑能完整执行。

关于FileList原型的补充

你问的“给FileList对象类型编写原型”,其实上面的代码已经用到了:Object.create(FileList.prototype)就是让我们构造的对象继承FileList的原型方法,这样它的行为和原生FileList完全一致,路由器的JS不会察觉到异常。如果需要扩展FileList的方法(比如添加自定义的遍历方法),也可以直接修改FileList.prototype,不过在这个场景里完全没必要,构造符合接口的对象就足够了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 08:25:50