Greasy Fork

Greasy Fork is available in English.

网页基于xpath|文本的自动点击(持续更新)

根据输入的XPath定位元素进行循环点击,可控制开始和停止,搜索不到元素时提示并停止,增加关闭按钮及可设置延时功能,优化XPath查找逻辑,添加界面可拖动伸缩、缩小功能及按指定文本查找点击元素功能,并美化界面布局

当前为 2024-12-12 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         网页基于xpath|文本的自动点击(持续更新)
// @namespace    https://game.lpengine.cn/*
// @version      1.0.1
// @description  根据输入的XPath定位元素进行循环点击,可控制开始和停止,搜索不到元素时提示并停止,增加关闭按钮及可设置延时功能,优化XPath查找逻辑,添加界面可拖动伸缩、缩小功能及按指定文本查找点击元素功能,并美化界面布局
// @author       toyourtomorrow
// @match        https://fz.lpengine.cn/*
// @match        https://game.lpengine.cn/*
// @match        *://*/*
// @grant        GM_setValue
// @grant        GM.getValue
// @grant        GM_addStyle
// ==/UserScript==

(function () {
    'use strict';

    // 创建用于输入XPath、延时、指定文本以及显示状态的HTML元素,并设置样式使其在最上方显示,同时设置初始为可拖动状态
    const inputDiv = document.createElement('div');
    inputDiv.style.position = 'fixed';
    inputDiv.style.top = '10px';
    inputDiv.style.left = '10px';
    inputDiv.style.zIndex = '9999';
    inputDiv.style.backgroundColor = '#f8f9fa';
    inputDiv.style.padding = '10px';
    inputDiv.style.borderRadius = '5px';
    inputDiv.style.boxShadow = '0 0 5px rgba(0, 0, 0, 0.2)';
    inputDiv.style.userSelect = 'none';  // 防止文本被误选
    inputDiv.draggable = true;  // 设置可拖动

    inputDiv.innerHTML = `
        <div style="display: flex; flex-direction: column;">
            <!-- XPath 相关 -->
            <div style="display: flex; align-items: center; margin-bottom: 10px;">
                <label for="xpathInput" style="margin-right: 10px;">XPath表达式:</label>
                <input type="text" id="xpathInput" style="padding: 5px; border: 1px solid #ced4da; border-radius: 3px; width: 300px;" />
            </div>
            <div style="display: flex; align-items: center; margin-bottom: 10px;">
                <label for="xpathDelayInput" style="margin-right: 10px;">XPath延时(毫秒):</label>
                <input type="number" id="xpathDelayInput" style="padding: 5px; border: 1px solid #ced4da; border-radius: 3px; width: 100px;" value="300" />
            </div>
            <div style="display: flex; align-items: center;">
                <button id="startXPathButton" style="padding: 5px 10px; border: none; border-radius: 3px; background-color: #007bff; color: white; cursor: pointer;">开始点击(XPath)</button>
                <button id="stopXPathButton" style="padding: 5px 10px; border: none; border-radius: 3px; background-color: #dc3545; color: white; cursor: pointer;">停止点击(XPath)</button>
            </div>

            <!-- 文本相关 -->
            <div style="display: flex; align-items: center; margin-top: 15px; margin-bottom: 10px;">
                <label for="textInput" style="margin-right: 10px;">指定文本:</label>
                <input type="text" id="textInput" style="padding: 5px; border: 1px solid #ced4da; border-radius: 3px; width: 200px;" />
            </div>
            <div style="display: flex; align-items: center; margin-bottom: 10px;">
                <label for="textDelayInput" style="margin-right: 10px;">文本延时(毫秒):</label>
                <input type="number" id="textDelayInput" style="padding: 5px; border: 1px solid #ced4da; border-radius: 3px; width: 100px;" value="300" />
            </div>
            <div style="display: flex; align-items: center;">
                <button id="startTextButton" style="padding: 5px 10px; border: none; border-radius: 3px; background-color: #28a745; color: white; cursor: pointer;">开始点击(文本)</button>
                <button id="stopTextButton" style="padding: 5px 10px; border: none; border-radius: 3px; background-color: #6c757d; color: white; cursor: pointer;">停止点击(文本)</button>
            </div>

            <button id="closeButton" style="padding: 5px 10px; border: none; border-radius: 3px; background-color: #6c757d; color: white; cursor: pointer; margin-top: 15px;">关闭</button>
            <button id="minimizeButton" style="padding: 5px 10px; border: none; border-radius: 3px; background-color: #6c757d; color: white; cursor: pointer; margin-top: 5px;">缩小</button>
            <span id="status" style="margin-left: 10px; color: #6c757d; margin-top: 10px;">状态: 未开始</span>
        </div>
    `;
    document.body.appendChild(inputDiv);

    // 用于记录鼠标按下时的坐标,实现拖动功能
    let startX, startY;

    // 为可拖动元素添加鼠标按下、移动和抬起事件监听器,正确实现拖动功能
    inputDiv.addEventListener('mousedown', function (e) {
        startX = e.clientX;
        startY = e.clientY;
        document.addEventListener('mousemove', drag);
        document.addEventListener('mouseup', stopDrag);
    });

    function drag(e) {
        const dx = e.clientX - startX;
        const dy = e.clientY - startY;
        inputDiv.style.left = (parseInt(inputDiv.style.left) || 0) + dx + 'px';
        inputDiv.style.top = (parseInt(inputDiv.style.top) || 0) + dy + 'px';
        startX = e.clientX;
        startY = e.clientY;
    }

    function stopDrag() {
        document.removeEventListener('mousemove', drag);
        document.removeEventListener('mouseup', stopDrag);
    }

    // 记录界面是否最小化
    let isMinimized = false;

    // 缩小按钮点击事件处理函数
    function minimize() {
        if (isMinimized) {
            // 如果已最小化,恢复原始大小
            inputDiv.style.width = 'auto';
            inputDiv.style.height = 'auto';
            isMinimized = false;
        } else {
            // 如果未最小化,缩小界面
            inputDiv.style.width = '30px';
            inputDiv.style.height = '30px';
            isMinimized = true;
        }
    }

    // 获取相关DOM元素
    const xpathInput = document.getElementById('xpathInput');
    const xpathDelayInput = document.getElementById('xpathDelayInput');
    const startXPathButton = document.getElementById('startXPathButton');
    const stopXPathButton = document.getElementById('stopXPathButton');
    const textInput = document.getElementById('textInput');
    const textDelayInput = document.getElementById('textDelayInput');
    const startTextButton = document.getElementById('startTextButton');
    const stopTextButton = document.getElementById('stopTextButton');
    const closeButton = document.getElementById('closeButton');
    const minimizeButton = document.getElementById('minimizeButton');
    const statusSpan = document.getElementById('status');

    // 初始化保存的XPath值、延时值和指定文本值(如果存在)
    (async () => {
        const savedXPath = await GM.getValue('savedXPath', '');
        const savedXPathDelay = await GM.getValue('savedXPathDelay', 300);
        const savedText = await GM.getValue('savedText', '');
        const savedTextDelay = await GM.getValue('savedTextDelay', 300);
        xpathInput.value = savedXPath;
        xpathDelayInput.value = savedXPathDelay;
        textInput.value = savedText;
        textDelayInput.value = savedTextDelay;
    })();

    // 递归遍历所有节点(包括跨iframe、处理Shadow DOM等)查找元素的函数(XPath方式)
    function findElementsByXPathInAllContexts(xpath, context = document) {
        const results = [];
        const iterate = (node) => {
            const elements = document.evaluate(xpath, node, null, XPathResult.ANY_TYPE, null).iterateNext();
            while (elements) {
                results.push(elements);
                elements = document.evaluate(xpath, node, null, XPathResult.ANY_TYPE, null).iterateNext();
            }
            const shadowRoots = node.querySelectorAll('*');
            shadowRoots.forEach((element) => {
                if (element.shadowRoot) {
                    iterate(element.shadowRoot);
                }
            });
            const iframes = node.querySelectorAll('iframe');
            for (const iframe of iframes) {
                try {
                    const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
                    iterate(iframeDoc);
                } catch (error) {
                    continue;
                }
            }
        };
        iterate(context);
        return results;
    }

    // 递归遍历所有节点(包括跨iframe、处理Shadow DOM等)查找包含指定文本元素的函数
    function findElementsByTextInAllContexts(text, context = document) {
        const results = [];
        const iterate = (node) => {
            const elements = node.querySelectorAll('*');
            elements.forEach((element) => {
                if (element.textContent.includes(text)) {
                    results.push(element);
                }
            });
            const shadowRoots = node.querySelectorAll('*');
            shadowRoots.forEach((element) => {
                if (element.shadowRoot) {
                    iterate(element.shadowRoot);
                }
            });
            const iframes = node.querySelectorAll('iframe');
            for (const iframe of iframes) {
                try {
                    const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
                    iterate(iframeDoc);
                } catch (error) {
                    continue;
                }
            }
        };
        iterate(context);
        return results;
    }

    // 等待页面加载完成(包括所有资源、iframe等加载完毕)后再执行查找等操作的函数
    function waitForPageLoad(callback) {
        if (document.readyState === 'complete') {
            callback();
        } else {
            window.addEventListener('load', callback);
        }
    }

    // 开始点击的函数(基于XPath)
    async function startClickingByXPath() {
        const xpath = xpathInput.value;
        const delay = parseInt(xpathDelayInput.value, 10);
        GM_setValue('savedXPath', xpath);
        GM_setValue('savedXPathDelay', delay);

        let intervalId;
        try {
            waitForPageLoad(() => {
                intervalId = setInterval(async () => {
                    const elements = findElementsByXPathInAllContexts(xpath);
                    if (elements.length > 0) {
                        for (const element of elements) {
                            element.click();
                        }
                    } else {
                        clearInterval(intervalId);
                        alert('未找到匹配XPath的元素,已停止点击。');
                        statusSpan.textContent = '状态: 已停止(未找到元素)';
                    }
                }, delay);
                statusSpan.textContent = '状态: 正在点击(XPath)';
            });
        } catch (error) {
            clearInterval(intervalId);
            alert('执行过程出现错误,请检查XPath表达式是否正确。');
            statusSpan.textContent = '状态: 已停止(出错)';
        }
    }

    // 开始点击的函数(基于指定文本)
    async function startClickingByText() {
        const text = textInput.value;
        const delay = parseInt(textDelayInput.value, 10);
        GM_setValue('savedText', text);
        GM_setValue('savedTextDelay', delay);

        let intervalId;
        try {
            waitForPageLoad(() => {
                intervalId = setInterval(async () => {
                    const elements = findElementsByTextInAllContexts(text);
                    if (elements.length > 0) {
                        for (const element of elements) {
                            element.click();
                        }
                    } else {
                        clearInterval(intervalId);
                        alert('未找到包含指定文本的元素,已停止点击。');
                        statusSpan.textContent = '状态: 已停止(未找到元素)';
                    }
                }, delay);
                statusSpan.textContent = '状态: 正在点击(文本)';
            });
        } catch (error) {
            clearInterval(intervalId);
            alert('执行过程出现错误,请检查输入的文本是否正确。');
            statusSpan.textContent = '状态: 已停止(出错)';
        }
    }

    // 为开始按钮(XPath方式)添加点击事件监听器
    startXPathButton.addEventListener('click', startClickingByXPath);

    // 为停止按钮(XPath方式)添加点击事件监听器
    stopXPathButton.addEventListener('click', () => {
        if (window.xPathIntervalId) {
            clearInterval(window.xPathIntervalId);
            statusSpan.textContent = '状态: 已停止';
        }
    });

    // 为开始按钮(文本方式)添加点击事件监听器
    startTextButton.addEventListener('click', startClickingByText);

    // 为停止按钮(文本方式)添加点击事件监听器
    stopTextButton.addEventListener('click', () => {
        if (window.textIntervalId) {
            clearInterval(window.textIntervalId);
            statusSpan.textContent = '状态: 已停止';
        }
    });

    // 为关闭按钮添加点击事件监听器,点击后移除整个输入框区域
    closeButton.addEventListener('click', () => {
        inputDiv.remove();
    });

    // 为缩小按钮添加点击事件监听器
    minimizeButton.addEventListener('click', minimize);
})();