如何跟踪和收集特定字段的所有使用的依赖JavaScript



我想收集所有事件和JavaScript代码的依赖关系为一个特定的表单字段/所有表单字段包括框架。我曾尝试使用puppeteer和CDP来获取字段的事件,然后收集JavaScript。我成功地获得了事件细节。不确定如何从事件遍历所有跟踪以收集使用过的JavaScript代码。感谢您的帮助。

下面的代码用于收集事件。

listener = await windowHandle._client.send('DOMDebugger.getEventListeners', {
objectId: submitElementHandle._remoteObject.objectId
});

另一个变种,更黑客,更不可靠。

import puppeteer from 'puppeteer';
const browser = await puppeteer.launch(/* { headless: false, defaultViewport: null } */);
try {
const [page] = await browser.pages();
// Hook on setting listeners.
await page.evaluateOnNewDocument(() => {
window._puppeteerListenersMap = new Map();
const _puppeteerOldAddEventListener = EventTarget.prototype.addEventListener;
EventTarget.prototype.addEventListener = function newAddEventListener(...args) {
const element = this;
const [eventName, eventListener] = args;
if (!_puppeteerListenersMap.get(element)) {
_puppeteerListenersMap.set(element, Object.create(null));
}
const allListeners = _puppeteerListenersMap.get(element);
allListeners[eventName] ??= [];
allListeners[eventName].push(eventListener);
_puppeteerOldAddEventListener.call(this, ...args);
};
});
await page.goto('https://example.org/');
// Test setting listeners.
await page.evaluate(() => {
document.body.addEventListener('click', function click() {
console.log('addEventListener click');
});
document.body.addEventListener('dblclick', function dblclick() {
console.log('addEventListener dblclick');
});
document.body.onclick = function onclick() { console.log('onclick'); };
document.body.ondblclick = function ondblclick() { console.log('ondblclick'); };
});
// Test getting listeners.
const data = await page.evaluate(() => {
const element = document.body;
const elementListeners = Object.create(null);
const allListeners = _puppeteerListenersMap.get(element);
if (allListeners) {
for (const [eventName, eventListeners] of Object.entries(allListeners)) {
elementListeners[eventName] = eventListeners.map(
eventListener => eventListener.toString()
);
}
}
for (const name in element) {
if (name.startsWith('on') &&
element[name] !== null &&
typeof element[name] === 'function'
) {
elementListeners[name] = element[name].toString();
}
}
return elementListeners;
});
console.log(JSON.stringify(data, null, '  '));
} catch (err) { console.error(err); } finally { await browser.close(); }

输出:

{
"click": [
"function click() {n      console.log('addEventListener click');n    }"
],
"dblclick": [
"function dblclick() {n      console.log('addEventListener dblclick');n    }"
],
"onclick": "function onclick() { console.log('onclick'); }",
"ondblclick": "function ondblclick() { console.log('ondblclick'); }"
}

乌利希期刊指南。测试来自codepen:

的页面
// Test getting listeners.
const data = await page.evaluate(() => {
const element = document.querySelector('#signup_v1-email');
element.value = 'foo'; // Input invalid email.
const elementListeners = Object.create(null);
const allListeners = _puppeteerListenersMap.get(element);
if (allListeners) {
for (const [eventName, eventListeners] of Object.entries(allListeners)) {
elementListeners[eventName] = eventListeners.map(
eventListener => (
eventListener.call(element, new Event(eventName)), // 'not a valid email' in Browser console.
eventListener.toString()
)
);
}
}
for (const name in element) {
if (name.startsWith('on') &&
element[name] !== null &&
typeof element[name] === 'function'
) {
elementListeners[name] = element[name].toString();
}
}
return elementListeners;
});

这是所有我可以从Chrome DevTools协议文档:

import puppeteer from 'puppeteer';
const browser = await puppeteer.launch();
try {
const [page] = await browser.pages();
const cdp = await page.target().createCDPSession();
await cdp.send('Debugger.enable');
const scriptIdToUrlMap = new Map();
cdp.on('Debugger.scriptParsed', ({ scriptId, url }) => {
scriptIdToUrlMap.set(scriptId, url);
});
await page.goto('https://chromedevtools.github.io/devtools-protocol/tot/DOMDebugger/');
await page.waitForSelector('body > main');
const { objectId } = (await cdp.send('Runtime.evaluate', {
expression: 'document.querySelector("body > main")',
})).result;
const { listeners } = await cdp.send('DOMDebugger.getEventListeners', { objectId });
for (const listener of listeners) {
console.log('Listener details:', listener, 'n');
console.log('Script URL:', scriptIdToUrlMap.get(listener.scriptId), 'n');
const { scriptSource } = await cdp.send('Debugger.getScriptSource', {
scriptId: listener.scriptId,
});
console.log(
'Script source start:',
scriptSource.split('n')[listener.lineNumber].slice(listener.columnNumber),
'...n',
);
}
} catch (err) { console.error(err); } finally { await browser.close(); }

当前输出:

Listener details: {
type: 'click',
useCapture: false,
passive: false,
once: false,
scriptId: '4',
lineNumber: 181,
columnNumber: 649
}
Script URL: https://chromedevtools.github.io/devtools-protocol/scripts/index.js
Script source start: (){I.classList.contains("shown")&&(I.classList.remove("shown"),P.focus())}document.addEventListener("keydown",e=>{e.metaKey||e.ctrlKey||e.altKey||(e.keyCode>=65&&e.keyCode<=90&&document.querySelector("cr-search-control").inputElement.focus(),"Escape"===e.key&&I.classList.contains("shown")&&I.classList.remove("shown"))}),P.addEventListener("click",e=>{e.stopPropagation(),I.addEventListener("transitionend",()=>{O.focus()},{once:!0}),I.classList.add("shown")}),B.addEventListener("click",W),O.addEventListener("click",W); ...

最新更新