解除网页禁止选中/复制限制

通用解除网页禁止选中文本、复制文本、右键菜单、快捷键等所有限制。支持 CSS user-select、事件拦截、快捷键封锁、剪贴板清空等全部手段。

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

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

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

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

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

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

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

Advertisement:

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

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

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

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

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

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

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

Advertisement:

// ==UserScript==
// @name         Unlock Text Selection & Copy
// @name:zh-CN   解除网页禁止选中/复制限制
// @name:en      Unlock Text Selection & Copy
// @namespace    https://alicexia.app/
// @version      2.0.0
// @description  Universal unlock for text selection, copy, right-click menu, and keyboard shortcuts. Defeats CSS user-select, event interception, key blocking, and clipboard clearing.
// @description:zh-CN 通用解除网页禁止选中文本、复制文本、右键菜单、快捷键等所有限制。支持 CSS user-select、事件拦截、快捷键封锁、剪贴板清空等全部手段。
// @author       alicexia
// @match        https://*.hotjob.cn/*
// @match        https://*.zhiye.com/*
// @match        https://*.iguopin.com/*
// @grant        none
// @run-at       document-start
// @license      MIT
// @contributionURL https://github.com/alicexiacn
// @homepageURL  https://github.com/alicexiacn/unlock-copy
// @supportURL   https://github.com/alicexiacn/unlock-copy/issues
// @icon         data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%234CAF50' d='M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z'/%3E%3C/svg%3E
// @compatible   chrome
// @compatible   edge
// @compatible   firefox
// @compatible   opera
// @compatible   safari
// ==/UserScript==

(function () {
    'use strict';

    // ============================================================
    // 第一层:CSS 防护解除
    // 覆盖 user-select: none / pointer-events: none
    // ============================================================
    function injectCSS() {
        var style = document.createElement('style');
        style.id = 'wb-unlock-select-style';
        style.textContent = [
            '*, *::before, *::after {',
            '    -webkit-user-select: text !important;',
            '    -moz-user-select: text !important;',
            '    -ms-user-select: text !important;',
            '    user-select: text !important;',
            '    -webkit-touch-callout: default !important;',
            '    pointer-events: auto !important;',
            '}'
        ].join('\n');
        (document.head || document.documentElement).appendChild(style);
    }

    // ============================================================
    // 第二层:事件拦截解除
    // 在捕获阶段(capture)用 stopImmediatePropagation 阻断
    // 网站自己注册的 contextmenu / selectstart / copy 等监听器
    // ============================================================
    var blockedEvents = [
        'contextmenu',      // 右键菜单
        'selectstart',      // 开始选中
        'select',           // 选中过程
        'copy',             // 复制
        'cut',              // 剪切
        'paste',            // 粘贴
        'dragstart',        // 拖拽
        'beforecopy',       // 复制前
        'beforecut',        // 剪切前
        'beforepaste',      // 粘贴前
        'mousedown',        // 鼠标按下(部分网站用它阻止选区起点)
        'mouseup'           // 鼠标抬起
    ];

    // 对普通用户来说,mousedown/mouseup 全局拦截可能影响交互
    // 这里只阻断那些调用了 preventDefault 的处理
    blockedEvents.forEach(function (eventName) {
        document.addEventListener(eventName, function (e) {
            e.stopPropagation();
            // stopImmediatePropagation 会阻止同元素上后续注册的同类监听器执行
            // 但只对 selectstart / contextmenu / copy 等关键事件使用
            if (['contextmenu', 'selectstart', 'copy', 'cut', 'paste', 'dragstart'].indexOf(eventName) !== -1) {
                e.stopImmediatePropagation();
            }
            // 放行默认行为
            try { e.returnValue = true; } catch (_) {}
        }, true);  // true = 捕获阶段,比网站的监听器更早执行
    });

    // ============================================================
    // 第三层:快捷键解除
    // 阻断网站对 Ctrl+C / Ctrl+A / Ctrl+X / Ctrl+V 的拦截
    // ============================================================
    document.addEventListener('keydown', function (e) {
        if (e.ctrlKey || e.metaKey) {
            var key = (e.key || '').toLowerCase();
            if (['c', 'a', 'x', 'v', 'insert'].indexOf(key) !== -1) {
                e.stopPropagation();
                e.stopImmediatePropagation();
            }
        }
        // F12 / Ctrl+Shift+I / Ctrl+Shift+J / Ctrl+U 也一并放行
        if (e.key === 'F12' || (e.ctrlKey && e.shiftKey && ['i', 'j', 'c'].indexOf((e.key || '').toLowerCase()) !== -1) || (e.ctrlKey && (e.key || '').toLowerCase() === 'u')) {
            e.stopPropagation();
            e.stopImmediatePropagation();
        }
    }, true);

    // ============================================================
    // 第四层:清除内联事件处理器 & 保护剪贴板
    // ============================================================
    var inlineProps = [
        'oncontextmenu', 'onselectstart', 'oncopy', 'oncut',
        'onpaste', 'ondragstart', 'onmousedown', 'onmouseup',
        'onbeforecopy', 'onbeforecut', 'onbeforepaste'
    ];

    function clearInlineHandlers() {
        inlineProps.forEach(function (prop) {
            try {
                document[prop] = null;
                if (document.body) { document.body[prop] = null; }
                document.documentElement[prop] = null;
            } catch (_) {}
        });
    }

    // 用 Object.defineProperty 彻底锁死,防止网站重新赋值
    inlineProps.forEach(function (prop) {
        try {
            Object.defineProperty(document, prop, {
                get: function () { return null; },
                set: function () { /* 吞掉赋值 */ },
                configurable: true
            });
        } catch (_) {}
    });

    // ============================================================
    // 第五层:MutationObserver 持续监控
    // 部分网站会在 DOM 动态变化后重新注入限制
    // ============================================================
    var observer = new MutationObserver(function () {
        clearInlineHandlers();
    });

    function startObserver() {
        observer.observe(document.documentElement || document, {
            childList: true,
            subtree: true,
            attributes: true,
            attributeFilter: ['oncontextmenu', 'onselectstart', 'oncopy', 'oncut',
                              'onpaste', 'ondragstart', 'style']
        });
    }

    // ============================================================
    // 初始化:多个时机执行,确保覆盖所有加载阶段
    // ============================================================
    // 1. 立即注入 CSS(document-start 时 head 可能还不存在,先放 html 上)
    injectCSS();

    // 2. DOMContentLoaded 时清除内联事件 + 重新注入 CSS + 启动 Observer
    document.addEventListener('DOMContentLoaded', function () {
        clearInlineHandlers();
        injectCSS();
        startObserver();
    });

    // 3. window.load 时再补一次(处理懒加载脚本)
    window.addEventListener('load', function () {
        clearInlineHandlers();
        injectCSS();
    });

    // 4. 如果 document 已经 ready,立即执行
    if (document.readyState !== 'loading') {
        clearInlineHandlers();
        injectCSS();
        startObserver();
    }

    console.log('解除选中/复制限制脚本已加载 ✓');
})();