您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Capture and test Xpath locators
// ==UserScript== // @name Xpath Locator // @namespace http://tampermonkey.net/ // @version 1.0 // @description Capture and test Xpath locators // @author Maged Ahmed // @include * // @grant none // @noframes // @license MIT // ==/UserScript== let highlightElementCount = 0; let currentElement; let highlightInterval; let elements = []; let elementIndex = 0; const MENU = ` <br/> <br/> <fieldset> <legend>Find by xpath:</legend> <p><label> <textarea id="xpValue" placeholder="xpath: //*" rows="10" maxlength="9999"></textarea> </label></p> <p> <button id="xpElementFind" class="xpMenuBtn"><i class="fa fa-search"></i></button> <button id="xpElementPrev" class="xpMenuBtn"><i class="fa fa-arrow-left"></i></button> <button id="xpElementNext" class="xpMenuBtn"><i class="fa fa-arrow-right"></i></button> <button id="xpElementClear" class="xpMenuBtn"><i class="fa fa-close"></i></button> <button id="xpElementCopy" class="xpMenuBtn"><i class="fa fa-copy"></i></button> <span id="xpElementsCount"></span> </p> </fieldset> <fieldset> <legend>Capture xpath:</legend> <p> <label for="xpId">Add id</label> <input id="xpId" type="checkbox" checked="checked"/> </p> <p> <label for="xpName">Add name</label> <input id="xpName" type="checkbox" checked="checked"/> </p> <p> <label for="xpClass">Add class</label> <input id="xpClass" type="checkbox"/> </p> <p> <label for="xpType">Add type</label> <input id="xpType" type="checkbox"/> </p> <p><label for="xpText">Add text</label> <input id="xpText" type="checkbox"/> </p> <p> <label for="xpIndex">Add index</label> <input id="xpIndex" type="checkbox"/> </p> <p> <label for="xpLength">Xpath Length</label> <input type="number" id="xpLength" value="1" min="1" max="100"> </p> <p> <button id="xpCapture"><i class="fa fa-location-arrow"></i> Capture</button> <button id="xpUpdate"><i class="fa fa-refresh"></i> Update</button> </p> </fieldset> <fieldset class="xpElementData"> <legend>Element Properties</legend> <table> <col style="width:50px"> <tr> <td>Tag</td> <td><div id="xpElementTag" style="max-height:100px; overflow:scroll"></div></td> </tr> <tr> <td>Id</td> <td><div id="xpElementId" style="max-height:100px; overflow:scroll"></div></td> </tr> <tr> <td>Name</td> <td><div id="xpElementName" style="max-height:100px; overflow:scroll"></div></td> </tr> <tr> <td>Class</td> <td><div id="xpElementClass" style="max-height:100px; overflow:scroll"></div></td> </tr> <tr> <td>Type</td> <td><div id="xpElementType" style="max-height:100px; overflow:scroll"></div></td> </tr> <tr> <td>Text</td> <td><div id="xpElementText" style="max-height:100px; overflow:scroll"></div></td> </tr> <tr> <td>Xpath</td> <td><div id="xpElementXpath" style="max-height:100px; overflow:scroll"></div></td> </tr> </table> </fieldset> `; const SCRIPT_CSS = ` .selectedElement { color: lime !important; background-color: yellow !important; outline-offset: -2px !important; outline: 4px solid lime !important; } .capturedElement { color: aqua !important; background-color: yellow !important; outline-offset: -2px !important; outline: 4px solid aqua !important; } .xpMenu p, .xpMenu label, .xpMenu button, .xpMenu a, .xpMenu fieldset, .xpMenu div, .xpMenu span, .xpMenuLink a { font: 16px arial, sans-serif; margin: 0; padding: .5 1em; min-height: 1; border: 1px solid transparent; box-shadow: none; outline: none; color: white; } .xpMenuLink a:hover { text-decoration: none; left: 0; color: white; } .xpMenuLink a { position: fixed; left: -100px; transition: 0.3s; padding: 5px; width: 100px; text-decoration: none; color: CornflowerBlue; border-radius: 0 20px 20px 0; z-index: 999999; top: 0px ; background-color: CornflowerBlue; white-space: nowrap; box-sizing: initial; } a.xpMenuLinkOpened{ left: 0; color: white; } .xpMenu { height: 100%; width: 0; position: fixed; top: 0; left: 0; background-color: CornflowerBlue; overflow-x: hidden; transition: 0.5s; z-index: 999998; } .xpMenu a { text-decoration: none; font-size: 25px; color: black; display: block; transition: 0.3s; } .xpMenu a:hover { text-decoration: none; color: white; } .xpMenu .xpMenuClosebtn { color: DIMGRAY; position: absolute; top: 0; right: 25px; font-size: 36px; margin-left: 50px; cursor: pointer; } .xpMenu button { font-size: 14px !important; appearance: button !important; cursor: pointer !important; background-color: lightblue !important; } .xpMenu .xpMenuBtn { color: white !important; background-color: CornflowerBlue !important; border: 2px solid #6495ED !important; border-radius: 10px !important; } .xpMenu textarea { width: 100%; box-sizing: border-box; resize: vertical ; color: black; } .xpMenu fieldset { display: block; margin-inline-start: 2px; margin-inline-end: 2px; padding-block-start: 0.35em; padding-inline-start: 0.75em; padding-inline-end: 0.75em; padding-block-end: 0.625em; min-inline-size: min-content; border-width: 2px; border-style: groove; border-color: threedface; border-image: initial; } .xpMenu table { font: 14px arial, sans-serif; width: 100%; height: 100%; table-layout:fixed; } .xpMenu td div { font: 14px arial, sans-serif; } .xpMenu td { text-align: left; border: 1px solid white; word-wrap: break-word; white-space: pre-wrap; } `; function openNav() { // const currentPosition = window.scrollY; // window.scrollTo({ top: document.body.scrollHeight, behavior: 'smooth' }); // setTimeout(() => { window.scrollTo(0,currentPosition); }, Math.floor(document.body.scrollHeight/25)); document.getElementById("xpMenuLinkOpen").classList.add("xpMenuLinkOpened"); document.getElementById("xpMenu").style.width = "300px"; document.body.style.marginLeft = "300px"; document.querySelectorAll('*').forEach(function(node) { if (window.getComputedStyle(node, null).getPropertyValue('position') === 'fixed' && window.getComputedStyle(node, null).getPropertyValue('left') === "0px" && (node.id !== 'xpMenuLinkOpen' && node.id !== 'xpMenu')) { node.style.marginLeft = "300px"; } }); } function closeNav() { document.getElementById("xpMenuLinkOpen").classList.remove("xpMenuLinkOpened"); document.getElementById("xpMenu").style.width = "0"; document.body.style.marginLeft = "0"; document.querySelectorAll('*').forEach(function(node) { if (window.getComputedStyle(node, null).getPropertyValue('position') === 'fixed') { node.style.marginLeft = "0"; } }); clearAll(); } function getElementsByXpath(path) { const result = document.evaluate(path, document, null, XPathResult.ANY_TYPE, null); let node, nodes = []; while ((node = result.iterateNext())) { nodes.push(node); } return nodes; } function unHighlightElement() { if (currentElement instanceof HTMLElement) { clearInterval(highlightInterval); currentElement.classList.remove("capturedElement"); currentElement.classList.remove("selectedElement"); highlightInterval = null; } } function highlightElement() { currentElement.classList.toggle("selectedElement"); highlightElementCount++; if (highlightElementCount === 5) { clearInterval(highlightInterval); highlightElementCount = 0; highlightInterval = null; } } function findElements() { clearElements(); unsetCapture(); const xpath = document.getElementById("xpValue").value; elements = getElementsByXpath(xpath); elementIndex = 0; selectElement() } function nextElement() { if (elementIndex < elements.length - 1) { elementIndex++; selectElement() } } function prevElement() { if (elementIndex > 0) { elementIndex--; selectElement() } } function selectElement() { unHighlightElement(); if (elements.length > 0 && (currentElement = elements[elementIndex]) && currentElement instanceof HTMLElement) { currentElement.scrollIntoView({ behavior: "smooth", block: "center", inline: "center" }); document.getElementById("xpElementsCount").textContent = "[" + (elementIndex + 1) + " / " + elements.length + "]"; displayElementInfo(); highlightInterval = setInterval(function() { highlightElement(); }, 100); } else { document.getElementById("xpElementsCount").textContent = ''; } } function displayElementInfo() { document.getElementById("xpElementTag").textContent = currentElement.tagName; document.getElementById("xpElementId").textContent = currentElement.id; document.getElementById("xpElementName").textContent = currentElement.name; document.getElementById("xpElementClass").textContent = currentElement.className; document.getElementById("xpElementType").textContent = currentElement.type; document.getElementById("xpElementText").textContent = currentElement.textContent; document.getElementById("xpElementXpath").textContent = getXPath(currentElement, true, true, true, false, false, true, 5); } function clearElements() { unHighlightElement(); document.getElementById("xpElementsCount").textContent = ''; elements = []; elementIndex = 0; } function clearAll() { document.getElementById("xpValue").value = ''; clearElements(); unsetCapture(); } function unsetCapture() { unHighlightElement(); document.onmousemove = null; document.oncontextmenu = null; } function captureElement() { if (currentElement) { const xpId = document.getElementById("xpId").checked; const xpName = document.getElementById("xpName").checked; const xpClass = document.getElementById("xpClass").checked; const xpType = document.getElementById("xpType").checked; const xpText = document.getElementById("xpText").checked; const xpIndex = document.getElementById("xpIndex").checked; const xpLength = document.getElementById("xpLength").value; document.getElementById("xpValue").value = getXPath(currentElement, xpId, xpName, xpClass, xpType, xpText, xpIndex, xpLength); findElements(); } } function setCapture() { clearElements(); unsetCapture(); document.onmousemove = function(event) { if (currentElement) { currentElement.classList.remove("capturedElement"); } const target = event.target; target.classList.add("capturedElement"); currentElement = target; }; document.oncontextmenu = function() { unsetCapture(); captureElement(); return false }; } function copyXpath() { document.getElementById("xpValue").select(); document.execCommand("copy"); } function getXPath(element, getId, getName, getClass, getType, getText, getIndex, maxCount) { let uiElementText; let xpath = ''; let count = 0; while (element) { let pathIndex = ""; if (getIndex) { try { let index = 0; for (let sibling = element.previousSibling; sibling; sibling = sibling.previousSibling) { if (sibling.nodeType === Node.DOCUMENT_TYPE_NODE) { continue; } if (sibling.nodeName === element.nodeName) { ++index; } } pathIndex = (index ? "[" + (index + 1) + "]" : "[1]"); } catch (err) { continue; } } let nodeXpath = ''; try { if (element.id && getId) { nodeXpath += '@id=\"' + element.id + '\"'; } } catch (err) { } try { if (element.name && getName) { if (nodeXpath !== '') { nodeXpath += ' and '; } nodeXpath += '@name=\"' + element.name + '\"'; } } catch (err) { } try { if (element.hasAttribute("type") && typeof element.type !== 'undefined' && getType) { if (nodeXpath !== '') { nodeXpath += ' and '; } nodeXpath += '@type=\"' + element.type + '\"'; } } catch (err) { } try { if (element.className && nodeXpath === '' && getClass) { if (nodeXpath !== '') { nodeXpath += ' and '; } nodeXpath += '@class=\"' + element.className + '\"'; } } catch (err) { } try { if (element.textContent && element.textContent.length < 50 && element.textContent === element.innerHTML && getText) { uiElementText = element.textContent; try { uiElementText = uiElementText.trim(); } catch (err) { uiElementText = uiElementText.replace(/^\s+|\s+$/g, ''); } if (nodeXpath !== '') { nodeXpath += ' and '; } if (element.textContent === uiElementText && element.textContent.length > 0) { nodeXpath += 'text()=\"' + element.textContent + '\"'; } else { nodeXpath += 'normalize-space() = \"' + uiElementText + '\"'; } } else if (element.text && element.text.length < 50 && element.text === element.innerHTML && getText) { uiElementText = element.text; try { uiElementText = uiElementText.trim(); } catch (err) { uiElementText = uiElementText.replace(/^\s+|\s+$/g, ''); } if (uiElementText.length > 0) { if (nodeXpath !== '') { nodeXpath += ' and '; } if (element.text === uiElementText) { nodeXpath += 'contains(text(),\'' + uiElementText + '\')'; } else { nodeXpath += 'contains(normalize-space(),\'' + uiElementText + '\')'; } } } else if (element.innerText && element.innerText.length < 50 && element.innerText === element.innerHTML && getText) { uiElementText = element.innerText; try { uiElementText = uiElementText.trim(); } catch (err) { uiElementText = uiElementText.replace(/^\s+|\s+$/g, ''); } if (uiElementText.length > 0) { if (nodeXpath !== '') { nodeXpath += ' and '; } if (element.innerText === uiElementText) { nodeXpath += 'contains(text(),\'' + uiElementText + '\')'; } else { nodeXpath += 'contains(normalize-space(),\'' + uiElementText + '\')'; } } } else if (element.nodeName.toLocaleLowerCase() === "a" || count === 0) { uiElementText = element.textContent; try { uiElementText = uiElementText.trim().substring(0, 20); uiElementText = uiElementText.replace("'", "') and contains (.,'"); } catch (err) { uiElementText = uiElementText.replace(/^\s+|\s+$/g, ''); uiElementText = uiElementText.replace("'", "') and contains (.,'"); } if (uiElementText.length > 0) { if (nodeXpath !== '') { nodeXpath += ' and '; } if (element.textContent === uiElementText) { nodeXpath += 'contains(normalize-space(),\'' + uiElementText + '\')'; } else { nodeXpath += 'contains(.,\'' + uiElementText + '\')'; } } } } catch (err) { } /** Getting the Element's Tag Name **/ const currentElementTagName = element.nodeName.toLocaleLowerCase(); /** Building Xpath for the current Element Node **/ if (nodeXpath === '') { xpath = '/' + currentElementTagName + pathIndex + xpath; } else { xpath = '/' + currentElementTagName + pathIndex + '[' + nodeXpath + ']' + xpath; } /** Switching focus to parent node **/ element = element.parentElement; /** Incrementing the element counter and breaking the loop in case we reach the maximum number of elements defined by the user **/ count++; if (count >= maxCount) { break; } } window.captured = null; return '/' + xpath; } const link = document.createElement('link'); link.rel = 'stylesheet'; link.href = 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css'; document.head.appendChild(link); const s = document.createElement('style'); s.innerHTML = SCRIPT_CSS; document.head.appendChild(s); const xpMenuDiv = document.createElement("div"); xpMenuDiv.id = "xpMenuLink"; xpMenuDiv.className = "xpMenuLink"; document.body.appendChild(xpMenuDiv); const xpMenuLink = document.createElement("a"); xpMenuLink.id = "xpMenuLinkOpen"; xpMenuLink.innerHTML = "Xpath Locator"; xpMenuLink.onclick = openNav; xpMenuDiv.appendChild(xpMenuLink); const xpMenu = document.createElement("div"); xpMenu.className = "xpMenu"; xpMenu.id = "xpMenu"; xpMenu.innerHTML = MENU; document.body.appendChild(xpMenu); const xpCloseMenu = document.createElement("div"); xpCloseMenu.id = "xpMenuClosebtn"; xpCloseMenu.className = "xpMenuClosebtn"; xpCloseMenu.innerHTML = "×"; xpCloseMenu.onclick = closeNav; xpCloseMenu.href = "#"; xpMenu.appendChild(xpCloseMenu); document.getElementById("xpElementFind").onclick = findElements; document.getElementById("xpElementNext").onclick = nextElement; document.getElementById("xpElementPrev").onclick = prevElement; document.getElementById("xpElementClear").onclick = clearAll; document.getElementById("xpCapture").onclick = setCapture; document.getElementById("xpUpdate").onclick = captureElement; document.getElementById("xpElementCopy").onclick = copyXpath;