终于不用看到CSDN该死的弹窗限制了

📅 2026/7/8 12:47:03 👁️ 阅读次数 📝 编程学习
终于不用看到CSDN该死的弹窗限制了

🧑‍💻 写在开头

点赞 + 收藏 === 学会🤣🤣🤣

想必大家在网上搜索解决问题解决方案时都会有这样的经历,明明找到了想要的解决问题的代码,想要一键复制到项目代码中,但有些网页限制了你的复制行为,可能让你登录账号、关注博主,更有甚者直接收费,其中比如CSDN,所以秉着互联网的开源精神我写个脚本来解决这问题,但由于个游览器的差异本文只针对我经常使用的Chrome游览器进行讲解。

开发脚本

根据对CSDN网页结构的了解我们主要针对包裹代码的<pre> 和 <code> 标签,还有网页对用户复制操作的监听的处理。

// ==UserScript==
// @name         终极复制解锁(捕获阶段拦截 + 全面清理)
// @namespace    http://tampermonkey.net/
// @version      1.6
// @description  彻底解除复制限制,包括 pre > code 无法复制的问题
// @author       You
// @match        *://*/*
// @grant        none
// @run-at       document-start
// ==/UserScript==(function() {'use strict';// 需要拦截的事件类型(这些事件常被用于限制复制)const BLOCKED_EVENTS = ['copy', 'cut', 'selectstart', 'contextmenu', 'selectionchange', 'mousedown', 'mouseup'];console.log(`脚本启动`);// ---------- 1. 捕获阶段拦截事件传播,但不阻止默认行为 ----------function stopPropagationOnly(e) {e.stopPropagation(); // 阻止事件传播到页面注册的监听器// 不调用 preventDefault,保证浏览器的默认复制行为能执行}BLOCKED_EVENTS.forEach(eventType => {document.addEventListener(eventType, stopPropagationOnly, true); // 捕获阶段window.addEventListener(eventType, stopPropagationOnly, true);});// ---------- 2. 拦截后续 addEventListener 调用 ----------const originalAddEventListener = EventTarget.prototype.addEventListener;EventTarget.prototype.addEventListener = function(type, listener, options) {if (BLOCKED_EVENTS.includes(type)) {console.log(`[解锁脚本] 已阻止添加事件: ${type}`);return; // 忽略添加}return originalAddEventListener.call(this, type, listener, options);};// ---------- 3. 清除已有事件属性和 CSS 限制 ----------function removeRestrictions(root) {if (!root) return;// 兼容 iframe 传入的 windowif (root.document) root = root.document;// 清理 document 对象if (root.nodeType === Node.DOCUMENT_NODE) {root.oncopy = null;root.oncut = null;root.onselectstart = null;root.oncontextmenu = null;root.onselectionchange = null;// 添加强制选择样式const style = root.createElement('style');style.innerHTML = `* {user-select: text !important;-webkit-user-select: text !important;-moz-user-select: text !important;-ms-user-select: text !important;}`;root.head.appendChild(style);} else {// 普通元素root.oncopy = null;root.oncut = null;root.onselectstart = null;root.oncontextmenu = null;root.onselectionchange = null;}// 处理 Shadow DOMif (root.shadowRoot) {removeRestrictions(root.shadowRoot);}// 遍历所有后代元素if (root.querySelectorAll) {root.querySelectorAll('*').forEach(el => {el.oncopy = null;el.oncut = null;el.onselectstart = null;el.oncontextmenu = null;el.onselectionchange = null;if (el.shadowRoot) {removeRestrictions(el.shadowRoot);}});}}// ---------- 4. 专门处理 pre 和 code 标签:克隆替换以移除所有事件监听器 ----------function unlockElements(root) {const selectors = ['pre', 'code'];selectors.forEach(selector => {const elements = root.querySelectorAll(`${selector}:not([data-unlocked])`);elements.forEach(el => {try {const clone = el.cloneNode(true);clone.setAttribute('data-unlocked', 'true');el.parentNode.replaceChild(clone, el);console.log(`[解锁脚本] 已替换 ${selector} 标签,移除了所有事件监听器`);} catch (e) {console.warn(`[解锁脚本] 替换 ${selector} 失败`, e);}});});}// 初始执行removeRestrictions(document);unlockElements(document);// ---------- 5. 观察动态添加的内容 ----------const observer = new MutationObserver(mutations => {mutations.forEach(mutation => {mutation.addedNodes.forEach(node => {if (node.nodeType === Node.ELEMENT_NODE) {removeRestrictions(node);unlockElements(node);}});});});if (document.body) {observer.observe(document.body, { childList: true, subtree: true });}// ---------- 6. 处理 iframe ----------function unlockIframes(root) {root.querySelectorAll('iframe').forEach(iframe => {try {const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;if (iframeDoc) {removeRestrictions(iframeDoc);unlockElements(iframeDoc);// 为 iframe 建立独立的观察者const iframeObserver = new MutationObserver(() => {removeRestrictions(iframeDoc);unlockElements(iframeDoc);});if (iframeDoc.body) {iframeObserver.observe(iframeDoc.body, { childList: true, subtree: true });}}} catch(e) {// 跨域 iframe 忽略}});}// 定期扫描 iframe 和重复清理(防止页面动态重置)setInterval(() => {unlockIframes(document);removeRestrictions(document);unlockElements(document);}, 2000);
})();

运行脚本

脚本开发完了就到了实战的时候了,要在游览器中运行写好的脚本文件,以下提供您两种方式,以下方法方案都需要用户打开Chrome的开发者模式方能使用。

打开Chrome的开发者模式 打开Chrome的开发者模式 打开Chrome的开发者模式 !!!重要的事情说三遍

工具运行

使用Chrome扩展工具 在Chrome扩展应用商城下载Tampermonkey,操作Tampermonkey新建脚本,将之前写的脚本代码放入新建的脚本文件中,保存完毕后使用以下方法在网页中运行

方法一:通过扩展管理页面开启 "允许用户脚本"

这是 Chrome 138+ 版本的标准操作方式

  1. 进入管理页:在 Chrome 右上角点击拼图图标,找到 Tampermonkey,点击右侧的 三个点,选择  "管理扩展程序"
  2. 查找开关:在 Tampermonkey 的详情页面里,向下滑动,找到  "允许用户脚本"  的开关。
  3. 开启:将其打开,然后完全重启一次 Chrome 浏览器 

方法二:在控制台强制执行(如果方法一无效)

如果在详情页找不到上述开关,或者开启后依然无效,可以尝试用命令强制激活 

  • 确保开发者模式已开:在地址栏输入 chrome://extensions/ 并回车,确认右上角的  "开发者模式"  处于开启状态 

  • 粘贴命令:按 F12 打开开发者工具,切换到 Console(控制台)  标签页,将以下代码完整粘贴进去并回车:

chrome.developerPrivate.updateExtensionConfiguration({extensionId: "dhdgffkkebhmkfjojejmpbldmpobfkfo",userScriptsAccess: true
});
  • 重启:执行完毕后,完全关闭 Chrome 并重新打开,再刷新网页试试 

直接运行

使用 "代码片段" 保存终极脚本(一劳永逸)

如果你经常需要面对复杂的复制限制(比如你之前提到的 <pre> 标签问题),每次在控制台输入一大段代码会很麻烦。Chrome 的  "代码片段(Snippets)"  功能可以完美解决这个问题,相当于一个内置的、轻量级的脚本管理器。

  1. 打开Snippets面板

    • 打开开发者工具(F12)。
    • 切换到 Sources(源代码)  标签页。
  2. 创建并保存脚本

    • 点击  "New snippet"(新建代码片段)
    • 将我之前为你提供的那个增强版终极脚本(包含了捕获阶段拦截、克隆替换 <pre><code> 标签、处理 Shadow DOM 等功能的完整代码)粘贴到右侧的编辑器中。
    • 按 Ctrl+S 保存,你可以给它起个名字,比如 终极复制解锁
  3. 运行脚本

    • 以后在任何遇到复制限制的网页,只需打开开发者工具 -> Sources -> Snippets,找到你保存的脚本,右键点击并选择  "Run"(运行) ,或者点击右下角的运行按钮(一个类似播放键的图标)即可。

这样,你就拥有了一个不需要 Tampermonkey 也能随时调用的 "终极解锁工具"。

如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。