绕过网页禁止粘贴的方法

JS逆向分析

目标页面通过 init_no_paste() 函数实现粘贴限制,核心逻辑包括:

  • 阻止右键菜单(contextmenu)
  • 禁用文本选择(selectstart)
  • 拦截粘贴事件(onpaste)并提示限制
  • 禁止拖拽功能(dragenter)

关键变量 _no_paste 控制限制开关,值为 “1” 时启用限制。

解决方法

方法一
刷新网页,在 JS 加载完成前快速粘贴(利用加载时序差)。

方法二:书签注入法
刷新网页后,点击提前设置的书签注入以下代码:

javascript:(function(){
  window.init_no_paste = function() {};
  document.onpaste = null;
  console.log("已解除粘贴限制 ✅");
})();
书签注入法复写JavaScript是一种在浏览器环境中,通过书签工具(Bookmarklet) 注入自定义代码,从而覆盖或修改网页原有JavaScript函数的技术。其核心原理是利用*浏览器书签的javascript:协议,将待执行的代码封装为可点击的书签,在目标网页上下文执行时,优先覆盖网页中原有的函数定义或事件绑定,从而绕过网页的功能限制(如禁用粘贴、右键等)。 具体来说,当用户点击书签时,封装的代码会在网页的全局作用域中运行,通过重写目标函数(如init_no_paste)或解除事件绑定(如document.onpaste),提前拦截网页原有的限制逻辑,使被禁用的功能(如粘贴)恢复正常。这种方法无需修改网页源码,仅通过浏览器自带的书签功能即可实现对JavaScript逻辑的动态复写,是前端调试和功能解锁的轻量型实用技巧。

Chrome 浏览器书签添加方法:

打开书签和清单
进入书签管理器
添加新书签

名称可根据需求随意设置,只需在书签的“网址”栏中填写封装好的JavaScript代码。使用时,需在网页加载阶段(如页面HTML已加载但目标JS未执行时)点击该书签,让注入的代码优先覆盖网页原有函数定义,从而实现功能复写。

方法三:油猴脚本注入

可借助Tampermonkey等浏览器脚本管理工具,将复写逻辑封装为油猴脚本。通过设置@run-at document-start(页面加载前执行),让脚本在网页原生JS加载前运行,从而从根源上覆盖目标函数,实现更持久、自动化的功能解锁。

方法四:Python脚本模拟输入

方法如题,只要不被检测到粘贴事件即可,这里附上python模拟输入的模板代码。

import tkinter as tk
from tkinter import ttk, messagebox
import pyautogui
import time
import threading

class PasteBypassTool:
    def __init__(self, root):
        self.root = root
        self.root.title("粘贴绕过工具")
        self.root.geometry("500x350")
        self.root.resizable(True, True)
        
        # 设置中文字体支持
        self.style = ttk.Style()
        self.style.configure("TLabel", font=("SimHei", 10))
        self.style.configure("TButton", font=("SimHei", 10))
        
        # 创建界面组件
        ttk.Label(root, text="请输入要模拟输入的文本:").pack(pady=10, anchor="w", padx=20)
        
        self.text_input = tk.Text(root, height=6, width=50, font=("SimHei", 10))
        self.text_input.pack(pady=5, padx=20, fill=tk.BOTH, expand=True)
        
        # 倒计时显示区域
        self.countdown_frame = ttk.Frame(root, height=60)
        self.countdown_frame.pack(pady=5, fill=tk.X)
        self.countdown_frame.pack_propagate(False)  # 防止框架大小被内容撑开
        
        self.countdown_var = tk.StringVar(value="")
        self.countdown_label = ttk.Label(
            self.countdown_frame, 
            textvariable=self.countdown_var, 
            font=("SimHei", 24, "bold")
        )
        self.countdown_label.pack(side=tk.TOP, pady=10)
        
        # 按钮区域
        button_frame = ttk.Frame(root)
        button_frame.pack(pady=10)
        
        self.start_btn = ttk.Button(
            button_frame, 
            text="开始模拟输入", 
            command=self.start_typing
        )
        self.start_btn.pack(side=tk.LEFT, padx=10)
        
        self.stop_btn = ttk.Button(
            button_frame, 
            text="停止", 
            command=self.stop_typing,
            state=tk.DISABLED
        )
        self.stop_btn.pack(side=tk.LEFT, padx=10)
        
        # 状态标签
        self.status_var = tk.StringVar(value="就绪,请输入文本并点击开始")
        ttk.Label(root, textvariable=self.status_var).pack(pady=5)
        
        # 控制变量
        self.is_typing = False
        self.typing_thread = None
        self.char_per_second = 10  # 每秒输入字符数
        self.delay = 1.0 / self.char_per_second  # 每个字符间隔时间

    def start_typing(self):
        """开始模拟输入"""
        text = self.text_input.get("1.0", tk.END).rstrip("\n")  # 获取文本并去除末尾换行
        
        if not text:
            messagebox.showwarning("警告", "请先输入要模拟的文本")
            return
            
        self.is_typing = True
        self.start_btn.config(state=tk.DISABLED)
        self.stop_btn.config(state=tk.NORMAL)
        self.status_var.set("准备开始,请切换到目标输入框")
        
        # 创建并启动线程
        self.typing_thread = threading.Thread(
            target=self._type_text, 
            args=(text,)
        )
        self.typing_thread.daemon = True
        self.typing_thread.start()

    def stop_typing(self):
        """停止模拟输入"""
        self.is_typing = False
        self.start_btn.config(state=tk.NORMAL)
        self.stop_btn.config(state=tk.DISABLED)
        self.status_var.set("已停止")
        self.countdown_var.set("")  # 清空倒计时显示

    def _update_countdown(self, value):
        """更新倒计时显示(在主线程中执行)"""
        self.countdown_var.set(str(value))
        
    def _type_text(self, text):
        """实际执行输入的函数,在单独线程中运行"""
        # 倒计时5秒,让用户有时间切换到目标窗口
        countdown_seconds = 5
        for i in range(countdown_seconds, 0, -1):
            if not self.is_typing:
                # 在主线程中更新UI
                self.root.after(0, self._update_countdown, "")
                return
            # 在主线程中更新UI
            self.root.after(0, self._update_countdown, i)
            time.sleep(1)
        
        # 清空倒计时显示
        self.root.after(0, self._update_countdown, "")
        self.root.after(0, lambda: self.status_var.set("正在输入..."))
        
        # 逐个字符输入
        for char in text:
            if not self.is_typing:
                break
            pyautogui.typewrite(char)
            time.sleep(self.delay)  # 控制输入速度
            
        if self.is_typing:  # 如果是正常完成而不是被停止
            self.root.after(0, lambda: self.status_var.set("输入完成"))
            self.root.after(0, lambda: self.start_btn.config(state=tk.NORMAL))
            self.root.after(0, lambda: self.stop_btn.config(state=tk.DISABLED))

if __name__ == "__main__":
    # 确保中文显示正常
    root = tk.Tk()
    app = PasteBypassTool(root)
    root.mainloop()

声明

仅供学习使用,批改网泛指各种的禁止粘贴的一些网站,其中禁止粘贴功能以一些需要原创内容限制而著名,因而泛指。


收录于知乎专栏「js逆向实例」· 查看知乎原文