文本选中复制
文本选中复制
某些网站例如某度文库、道客某某等都不允许用户选中文本进行复制,作为一个搞前端的,就感觉离谱,文本都下载到本地了,还不让我复制,于是为了更好的学(复)习(制),实现了一个脚本去解决这些限制。
描述
首先来看一下效果图,依旧是以某度文库、道客某某为例展示效果,点击复制按钮即可成功复制。
脚本下载地址:https://greasyfork.org/scripts/405130-文本选中复制 Github:https://github.com/WindrunnerMax/TKScript/tree/master/src/copy 脚本主要支持 百度文库 道客巴巴 无忧考网 学习啦 蓬勃范文 中文本的复制
实现
在研究实现之前,可能需要知道下面的一些知识,后面的链接是我之前写过的一些博客:
某度文库
在某度文库中直接右击检查元素的话,是能够直接看到文字的,可以直接在调试面板的Elements
审查元素中复制,但是总是有些麻烦。如果在选中某度文库的东西会弹出他自行插入的复制按钮,无论是按Ctrl+C
或者点击他的复制按钮都无效,除非开通一个VIP
,本着白嫖的原则,且文本都下载到浏览器了还不让复制有点说不过去,于是首先研究一下他的Event Listeners
。
虽然通过移除一些Event Listeners
确实能够达到使用Ctrl+C
来实现复制的效果,但是浏览器并不提供获取所有事件监听的方法,无法移除对于匿名的事件处理函数,对于具名的事件处理函数也不容易获取,谷歌浏览器提供的getEventListeners
方法也只能在Console
中使用,在脚本中会出现找不到该方法的异常,于是替换了一种方案,通过自行实现一个复制按钮来规避某度文库对于按键以及复制事件的屏蔽,具体是通过动态地插入Dom
实现一个按钮,然后使用ClipboardJS
这个插件去实现复制,其他的操作都是一些细节的处理,例如阻止这个插入的按钮继续冒泡触发onmouseup
事件等。
道客某某
不得不说,这个真的是惊到我了,他的实现是将文本加密,然后解密文本,最后通过使用Canvas
将文本绘制,拖动鼠标选中时其实只是通过事件监听动态的插入了一个淡蓝色的透明的div
,看似是选中了,实际文本是并未选中的。
见招拆招,既然文本都已经下载到了我本地,那么他的解密方式也必定在本地,于是我首先寻找的就是他对于加密的数据进行解密的代码,在浏览器中debug
了很长时间,因为他对于代码有加密混淆压缩的行为,解密的相关代码比较混乱,并不太容易去复现,于是我换了一个思路,既然VIP
是能够复制的,那么对于这个点击复制的按钮一定会有相应的事件处理函数,那么就寻找这个按钮绑定的事件处理函数,通过不断地debug
我定位了一个加密的Js
文件,虽然做了加密以及混淆但是将其解析并格式化之后在事件处理函数的部分不是特别影响阅读,此外他的混淆的变量名是动态生成的,所以要做的就是再次请求一遍这个Js
首先将其解析生成一段字符串然后通过正则表达式匹配正确的变量名,从而实现文本的复制。
其他
对于这一部分基本上都是通过监听一个oncopy
事件去拦截复制操作,对于DOM0
级模型直接将oncopy
事件的处理函数指向一个空函数即可,对于DOM2
级模型,前文提到无法在脚本中直接获取一个元素绑定的所有事件,通过观察这些网站的Event Listeners
可以发现其绑定的oncopy
事件都是绑定在document
上的,而且都是冒泡模型,那么只需要阻止事件向上冒泡就能规避这些网站的oncopy
事件的触发,实现方案就是在body
上定义oncopy
事件为一个空函数并阻止其向上冒泡。
Github
https://github.com/WindrunnerMax/TKScript
- mybatis的物理分页:mybatis-paginator
- 使用 WMI 进行诊断WCF
- java:快速文件分割及合并
- 暴涨210倍的一个数字货币正悄无声息崛起
- QT Creator 快速入门教程 读书笔记(一)
- .NET程序优化(GCServer )
- redis 学习笔记(4)-HA高可用方案Sentinel配置
- oracle: job使用
- velocity模板引擎学习(2)-velocity tools 2.0
- java:如何用代码控制H2 Database启动
- 游戏开发完整学习路线(各个版本都有)
- spring mvc4:异常处理
- TCP/IP, WebSocket 和 MQTT
- struts2: 玩转 rest-plugin
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 基于决策树的工业数据分类——数据智能
- Kestrel的ListenAnyIP和ListenLocalhost的区别
- 【为宏正名】什么?我忘了去上“数学必修课”!
- 第6章 Jenkins系统权限划分与授权管理
- Python爬虫新手教程: 知乎文章图片爬取器
- 《重构-代码整洁之道TypeScript版》第4天
- C++基础 杂记(一)
- 一种Cortex-M内核中的精确延时方法(ns级别)
- 算法集锦(17)|自然语言处理| 比特币市场情绪分析算法
- Linux匿名管道及实例
- 查找算法笔记(C++版)
- C++基础 指针使用注意
- FreeRTOS移植-基于STM32F407
- 感知机的股票预测算例及python代码实现 | 山人聊算法 | 5th
- C++基础 智能指针