# 浏览器插件跨框架(frame)上传文件的方法 **原理说明** 浏览器的cdp协议中有一个方法:DOM.setFileInputFiles,它可以实现自动上传文件路径。 DOM.setFileInputFiles有4个参数(files,nodeId,backendNodeId,objectId) 1.files:                          文件路径数组     必填 2.nodeId:                     节点ID                 选填 3.backendNodeId:      后端节点ID         选填 4.objectId:                   对象ID                  选填(Runtime.RemoteObjectId-运行时.远程对象ID) 使用时选填的参数必须选其中一项填写. 因为选填(2|3|4)的3项参数数据-可以通过不同的方式获取数据,所以该方法的使用方式可以有多种思路。 【方式一】  2.nodeId                --------》可以通过DOM.getDocument      -----》DOM.querySelector   【方式二】  3.backendNodeId --------》可以通过DOM.getFrameOwner -----》DOM.describeNode   【方式三】  4.objectId              --------》可以通过Runtime.evaluate      (这个获取方式非常有用,可以运行js代码,可以获取执行上下文 ID等) **这里使用【方式一】的方式上传文件** 现有两种思路 **第1种思路(单一框架)** 1.通过DOM.getDocument    chrome.debugger.sendCommand({tabId: tabId}, 'DOM.getDocument',{},(result) => {console.log(result);})   -------->获取顶层框架(tab页)的nodeId 2.通过DOM.querySelector(第1次用)    例如iframeCSS选择器(#iframe)         chrome.debugger.sendCommand({tabId: tabId}, 'DOM.querySelector',{nodeId: nodeId,selector:"#iframe"},(result) => {console.log(result);})  -------->获取到iframe的CSS选择器的nodeId,再nodeId=nodeId+1这样就获取跨框架的nodeId 3.通过DOM.querySelector(第2次用)      例如文件框CSS选择器(#fileInput)   注意这个是重点(跨框架的nodeId):nodeId=nodeId+1      chrome.debugger.sendCommand({tabId: tabId}, 'DOM.querySelector',{nodeId: nodeId,selector:"#fileInput"},(result) => {console.log(result);})  ---------  >  获取到文件框CSS选择器的nodeId 4.通过DOM.setFileInputFiles       例如设置文件路径["C:/Users/Administrator/Desktop/11.txt"]       chrome.debugger.sendCommand({tabId: tabId}, "DOM.setFileInputFiles", {nodeId:nodeId,"files":["C:/Users/Administrator/Desktop/11.txt"]} async function 上传文件1(e) {             let { tabId: t, iframeselector: r, fileInputselector: o, files:g } = e             var n={tabId: t}             let a= await chrome.debugger.attach(n, "1.3");             let l = await chrome.debugger.sendCommand(n, "DOM.getDocument", {});             l = await chrome.debugger.sendCommand(n,"DOM.querySelector", {"nodeId": l.root.nodeId,"selector":r});             l = await chrome.debugger.sendCommand(n,"DOM.querySelector", {"nodeId": l.nodeId+1,"selector":o});             l = await chrome.debugger.sendCommand(n, "DOM.setFileInputFiles", {"nodeId":l.nodeId,"files":g});             console.log("测试1"); } //参数说明 tabId:  调试目标 iframeselector:  iframe框架的css选择器 fileInputselector:  文件框的css选择器 files:  需要上传文件的路径数组 //参数示例 { tabId: 123654, iframeselector:"#iframe", fileInputselector:"#fileInput", files:["C:/Users/Administrator/Desktop/11.png"] } **第2种思路(多框架)** 1.通过DOM.getDocument    chrome.debugger.sendCommand({tabId: tabId}, 'DOM.getDocument',{},(result) => {console.log(result);})   -------->获取顶层框架(tab页)的nodeId 2.通过DOM.querySelectorAll       chrome.debugger.sendCommand({tabId: tabId}, 'DOM.querySelectorAll',{nodeId: nodeId,selector:"iframe"},(result) => {console.log(result);})  -------->获取到iframe框架的nodeIds数组,通过数组序号取出 如:nodeIds[1],再nodeId=nodeId+1这样就获取跨框架的nodeId 3.通过DOM.querySelector      例如文件框CSS选择器(#fileInput)   注意这个是重点(跨框架的nodeId):nodeId=nodeId+1      chrome.debugger.sendCommand({tabId: tabId}, 'DOM.querySelector',{nodeId: nodeId,selector:"#fileInput"},(result) => {console.log(result);})  ---------  >  获取到文件框CSS选择器的nodeId 4.通过DOM.setFileInputFiles       例如设置文件路径["C:/Users/Administrator/Desktop/222.txt"]       chrome.debugger.sendCommand({tabId: tabId}, "DOM.setFileInputFiles", {nodeId:nodeId,"files":["C:/Users/Administrator/Desktop/222.txt"]}) 2.1\*\*\*\*\*\*\*\*\*\*\*函数 async function 上传文件2(e) {             let { tabId: t, iframexh: r, fileInputselector: o, files:g } = e             var n={tabId: t}             let a= await chrome.debugger.attach(n, "1.3");             let l = await chrome.debugger.sendCommand(n, "DOM.getDocument", {});             l = await chrome.debugger.sendCommand(n,"DOM.querySelectorAll", {"nodeId": l.root.nodeId,"selector":"iframe"});             a=l.nodeIds[r];             l = await chrome.debugger.sendCommand(n,"DOM.querySelector", {"nodeId": a+1,"selector":o});             l = await chrome.debugger.sendCommand(n, "DOM.setFileInputFiles", {"nodeId":l.nodeId,"files":g});             console.log("测试2"); } //参数说明 tabId:  调试目标 iframexh:  iframe框架的序号如: 0|1|2|3 fileInputselector:  文件框的css选择器 files:  需要上传文件的路径数组 //参数示例 { tabId: 123654, iframexh:1, fileInputselector:"#fileInput", files:["C:/Users/Administrator/Desktop/22.png"] } 2.2\*\*\*\*\*\*\*\*\*\*\*\*\*\*函数 async function 上传文件3(e) {             let { tabId: t, fileInputselector: o, files:g } = e             var n={tabId: t}             await chrome.debugger.attach(n, "1.3");             let b1 = await chrome.debugger.sendCommand(n, "DOM.getDocument", {});             let b2 = await chrome.debugger.sendCommand(n,"DOM.querySelector", {"nodeId": b1.root.nodeId,"selector":o});             if (b2.nodeId ==0) {                         let b3 = await chrome.debugger.sendCommand(n,"DOM.querySelectorAll", {"nodeId": b1.root.nodeId,"selector":"iframe"});                        //console.log(“测试3”);                        await  循环框架(b3.nodeIds , n , o, g );              } else {                       await chrome.debugger.sendCommand(n, "DOM.setFileInputFiles", {"nodeId":b2.nodeId,"files":g});              } } async function 循环框架(aar , n , o , g ) {              for (let a of aar) {                 let b= await chrome.debugger.sendCommand(n,"DOM.querySelector", {"nodeId": a+1,"selector":o});                 if (b.nodeId >0) {                       await chrome.debugger.sendCommand(n, "DOM.setFileInputFiles", {"nodeId":b.nodeId,"files":g});                      //return;                 }        } } async function 循环框架1(aar, n, o, g) {     const promises = aar.map(async (a) => {         try {             let b = await chrome.debugger.sendCommand(n, "DOM.querySelector", {"nodeId": a+1, "selector": o});             if (b.nodeId > 0) {                 await chrome.debugger.sendCommand(n, "DOM.setFileInputFiles", {"nodeId": b.nodeId, "files": g});                 // return;             }         } catch (error) {             console.error('Error in 循环框架:', error);         }     }); await Promise.all(promises); } //参数说明 tabId:  调试目标 fileInputselector:  文件框的css选择器 files:  需要上传文件的路径数组 //参数示例 { tabId: 123654, fileInputselector:"#fileInput", files:["C:/Users/Administrator/Desktop/22.png"] } ![](https://files.getquicker.net/_sitefiles/kc/kb/2025/06/06/000728_689543_mceclip2.jpg)![](https://files.getquicker.net/_sitefiles/kc/kb/2025/06/06/000746_689543_mceclip3.jpg) 这是浏览器插件mv3版的,浏览器mv2版同样适用但其mv2版写法太过嵌套,不再编写了,原理是一样的。 目的是找到框架(iframe)里文件框css选择器的节点数值-----》nodeId , 然后使用chrome.debugger.sendCommand({tabId: tabId}, "DOM.setFileInputFiles", {"nodeId":nodeId,"files":["C:/Users/Administrator/Desktop/11.txt"]})设置文件路径,通过DOM.getDocument的参数{"pierce":true,"depth": -1}可以获取全部节点的nodeId,最终就是怎样获取到这个数值