原理说明
浏览器的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"]
}
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);
}
这是浏览器插件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,最终就是怎样获取到这个数值