Clic automático para ti

Hace clic automáticamente en elementos especificados en URLs que coinciden con una expresión regular.

Versión del día 12/6/2025. Echa un vistazo a la versión más reciente.

Tendrás que instalar una extensión para tu navegador como Tampermonkey, Greasemonkey o Violentmonkey si quieres utilizar este script.

Necesitarás instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Userscripts para instalar este script.

Necesitará instalar una extensión como Tampermonkey para instalar este script.

Necesitarás instalar una extensión para administrar scripts de usuario si quieres instalar este script.

(Ya tengo un administrador de scripts de usuario, déjame instalarlo)

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

(Ya tengo un administrador de estilos de usuario, déjame instalarlo)

// ==UserScript==
// @name         click it for you
// @name:zh-TW   click it for you
// @name:ja      あなたのためにクリック
// @name:en      click it for you
// @name:ko      당신을 위해 클릭
// @name:es      Clic automático para ti
// @description  在符合正則表達式的網址上自動點擊指定的元素。
// @description:zh-TW 在符合正則表達式的網址上自動點擊指定的元素。
// @description:ja 正規表現に一致するURLで指定された要素を自動的にクリックします。
// @description:en Automatically clicks specified elements on URLs matching a regular expression.
// @description:ko 정규 표현식과 일치하는 URL에서 지정된 요소를 자동으로 클릭합니다.
// @description:es Hace clic automáticamente en elementos especificados en URLs que coinciden con una expresión regular.

// @author       Max
// @namespace    https://github.com/Max46656

// @match        *://*/*
// @grant        GM_registerMenuCommand
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_info
// @version      1.0.0
// @license MPL2.0
// ==/UserScript==

class AutoClickManager {

    constructor() {
        this.clickRules = GM_getValue('clickRules', []);
        this.init();
    }

    clickRules;

    init(){
        this.registerMenu();
        this.runAutoClicks();
    }

    // 儲存組態至本地存儲
    saveConfigs() {
        GM_setValue('clickRules', this.clickRules);
    }

    // 根據選擇器類型獲取元素
    getElements(selectorType, selector) {
        if (selectorType === 'xpath') {
            const nodes = document.evaluate(selector, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
            const elements = [];
            for (let i = 0; i < nodes.snapshotLength; i++) {
                elements.push(nodes.snapshotItem(i));
            }
            return elements;
        } else if (selectorType === 'css') {
            return Array.from(document.querySelectorAll(selector));
        }
        return [];
    }

    // 執行單條規則的自動點擊
    autoClick(rule) {
        const urlRegex = new RegExp(rule.urlPattern);
        if (!urlRegex.test(window.location.href)) {
            return;
        }

        const elements = this.getElements(rule.selectorType, rule.selector);
        if (elements.length === 0) {
            console.warn(`${GM_info.script.name}:"${rule.ruleName}" 未找到符合元素:`, rule.selector);
            return;
        }

        if (rule.nthElement < 1 || rule.nthElement > elements.length) {
            console.warn(`${GM_info.script.name}:"${rule.ruleName}" 的 nthElement 無效:${rule.nthElement},找到 ${elements.length} 個元素`);
            return;
        }

        const targetElement = elements[rule.nthElement - 1];
        if (targetElement) {
            console.log(`${GM_info.script.name}:"${rule.ruleName}" 點擊元素:`, targetElement);
            targetElement.click();
        } else {
            console.warn(`${GM_info.script.name}:"${rule.ruleName}" 未找到目標元素`);
        }
    }

    // 執行所有符合規則的自動點擊
    runAutoClicks() {
        this.clickRules.rules.forEach((rule, index) => {
            if (rule.urlPattern && rule.selector) {
                setTimeout(() => this.autoClick(rule), rule.clickDelay || 1000);
            } else {
                console.warn(`${GM_info.script.name}:"${rule.ruleName}" 無效(索引 ${index}):缺少 urlPattern 或 selector`);
            }
        });
    }

    // 創建組態選單
    createMenu() {
        const menu = document.createElement('div');
        menu.style.position = 'fixed';
        menu.style.top = '10px';
        menu.style.right = '10px';
        menu.style.background = 'rgb(36, 36, 36)';
        menu.style.color = 'rgb(204, 204, 204)';
        menu.style.border = '1px solid rgb(80, 80, 80)';
        menu.style.padding = '10px';
        menu.style.zIndex = '10000';
        menu.style.maxWidth = '400px';
        menu.style.boxShadow = '0 0 10px rgba(0,0,0,0.5)';
        menu.innerHTML = `
                <style>
                    #autoClickMenu input, #autoClickMenu select, #autoClickMenu button {
                        background: rgb(50, 50, 50);
                        color: rgb(204, 204, 204);
                        border: 1px solid rgb(80, 80, 80);
                        margin: 5px 0;
                        padding: 5px;
                        width: 100%;
                        box-sizing: border-box;
                    }
                    #autoClickMenu button {
                        cursor: pointer;
                        margin-right: 5px;
                    }
                    #autoClickMenu button:hover {
                        background: rgb(70, 70, 70);
                    }
                    #autoClickMenu label {
                        margin-top: 5px;
                        display: block;
                    }
                    #autoClickMenu .ruleHeader {
                        cursor: pointer;
                        background: rgb(50, 50, 50);
                        padding: 5px;
                        margin: 5px 0;
                        border-radius: 3px;
                    }
                    #autoClickMenu .ruleDetails {
                        padding: 5px;
                        border: 1px solid rgb(80, 80, 80);
                        border-radius: 3px;
                        margin-bottom: 5px;
                    }
                </style>
                <div id="autoClickMenu">
                    <h3>設定自動點擊</h3>
                    <div id="rulesList"></div>
                    <h4>新增規則</h4>
                    <label>規則名稱:</label>
                    <input type="text" id="ruleName" placeholder="例如:我的規則">
                    <label>網址正則表達式:</label>
                    <input type="text" id="urlPattern" placeholder="例如:https://example\\.com/.*">
                    <label>選擇器類型:</label>
                    <select id="selectorType">
                        <option value="css">CSS</option>
                        <option value="xpath">XPath</option>
                    </select>
                    <label>選擇器:</label>
                    <input type="text" id="selector" placeholder="例如:button.submit 或 //button[@class='submit']">
                    <label>第幾個元素(從 1 開始):</label>
                    <input type="number" id="nthElement" min="1" value="1">
                    <label>點擊延遲(毫秒):</label>
                    <input type="number" id="clickDelay" min="0" value="1000">
                    <button id="addRule" style="margin-top: 10px;">新增規則</button>
                    <button id="closeMenu" style="margin-top: 10px;">關閉</button>
                </div>
            `;
        document.body.appendChild(menu);

        // 更新規則列表
        this.updateRulesList();

        // 新增規則按鈕事件
        document.getElementById('addRule').addEventListener('click', () => {
            const newRule = {
                ruleName: document.getElementById('ruleName').value || `規則 ${this.clickRules.rules.length + 1}`,
                urlPattern: document.getElementById('urlPattern').value,
                selectorType: document.getElementById('selectorType').value,
                selector: document.getElementById('selector').value,
                nthElement: parseInt(document.getElementById('nthElement').value) || 1,
                clickDelay: parseInt(document.getElementById('clickDelay').value) || 1000
            };
            this.clickRules.rules.push(newRule);
            this.saveConfigs();
            this.updateRulesList();
            document.getElementById('ruleName').value = '';
            document.getElementById('urlPattern').value = '';
            document.getElementById('selector').value = '';
            document.getElementById('nthElement').value = '1';
            document.getElementById('clickDelay').value = '1000';
        });

        // 關閉選單按鈕事件
        document.getElementById('closeMenu').addEventListener('click', () => {
            menu.remove();
        });
    }

    // 更新規則列表(僅顯示當前網址符合的規則)
    updateRulesList() {
        const rulesList = document.getElementById('rulesList');
        rulesList.innerHTML = '<h4>符合的規則</h4>';
        const currentUrl = window.location.href;
        const matchingRules = this.clickRules.rules.filter(rule => {
            try {
                return new RegExp(rule.urlPattern).test(currentUrl);
            } catch (e) {
                console.error(`${GM_info.script.name}:規則 "${rule.ruleName}" 的正則表達式無效:`, rule.urlPattern);
                return false;
            }
        });

        if (matchingRules.length === 0) {
            rulesList.innerHTML += '<p>當前網址無符合的規則。</p>';
            return;
        }

        matchingRules.forEach((rule, index) => {
            const globalIndex = this.clickRules.rules.indexOf(rule);
            const ruleDiv = document.createElement('div');
            ruleDiv.innerHTML = `
                    <div class="ruleHeader" id="ruleHeader${globalIndex}">
                        <strong>${rule.ruleName || `規則 ${globalIndex + 1}`}</strong>
                    </div>
                    <div class="ruleDetails" id="ruleDetails${globalIndex}" style="display: none;">
                        <strong>規則 ${globalIndex + 1}</strong><br>
                        名稱:${rule.ruleName || '未命名'}<br>
                        網址:${rule.urlPattern}<br>
                        類型:${rule.selectorType}<br>
                        選擇器:${rule.selector}<br>
                        第幾個元素:${rule.nthElement}<br>
                        延遲:${rule.clickDelay}毫秒<br>
                        <button id="deleteRule${globalIndex}">刪除</button>
                    </div>
                `;
            rulesList.appendChild(ruleDiv);

            // 為規則標題添加點擊事件(縮小/展開)
            document.getElementById(`ruleHeader${globalIndex}`).addEventListener('click', () => {
                const details = document.getElementById(`ruleDetails${globalIndex}`);
                details.style.display = details.style.display === 'none' ? 'block' : 'none';
            });

            // 為刪除按鈕添加點擊事件
            document.getElementById(`deleteRule${globalIndex}`).addEventListener('click', () => {
                this.clickRules.rules.splice(globalIndex, 1);
                this.saveConfigs();
                this.updateRulesList();
            });
        });
    }

    // 註冊選單命令
    registerMenu() {
        GM_registerMenuCommand('組態自動點擊', () => this.createMenu());
    }
}

const johnTheYubisaku = new AutoClickManager();