Chrome浏览器扩展实践之CSDN篇(解除关注限制、破解复制)

AI摘要:

简介

​ Chrome浏览器扩展是Google Chrome浏览器的浏览器扩展程序,可以在以Chrome为内核的浏览器中运行,包括Chrome、Edge等,能够增强Chrome浏览器的功能,通过添加新的按钮、工具栏、侧边栏、选项页等用户界面元素,或者通过修改网页内容、样式和行为,为用户提供更加个性化、高效和便捷的浏览体验。

文件夹内容

├─ CSDN取消关注限制
……..├─ manifest.json
……..├─ background.js
……..├─ content-script.js
……..├─ popup.html
……..├─ popup.js
……..├─ style.css
……..└─ images

manifest.json

manifest.json 是 Chrome 浏览器扩展(以及其他基于 Chromium 的浏览器,如 Edge)的核心文件。它包含了扩展的元数据、版本信息、所需权限、背景脚本、内容脚本等。

当更改 manifest.json 文件后,通常需要重新加载扩展才能看到更改的效果。在 Chrome 中,可以通过“扩展程序”页面(chrome://extensions/)的“重新加载”按钮来做到这一点。

完整的配置文档请戳这里

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
{
// 插件的名称
"name": "CNDS无需关注",

// 插件描述
"description": "解锁关注后查看限制",

// 插件的版本
"version": "0.1.1",

// 清单文件的版本,一般为3,2已经弃用
"manifest_version": 3,

// 图标,一般偷懒全部用一个尺寸的也没问题
"icons":
{
"16": "/images/icon.png",
"48": "/images/icon.png",
"128": "/images/icon.png"
},

// 会一直常驻的后台JS或后台页面
"background":
{
"service_worker": "./background.js"
},

// 浏览器右上角图标设置
"action":
{
"default_popup": "popup.html",
"default_icon ": "/images/icon.png",
"default_title": "CNDS无需关注"
},

// 权限申请
"permissions":
[
"storage",
"tabs",
"scripting",
"notifications"
],

//可以访问的网站
"host_permissions":
[
"<all_urls>",
"https://blog.csdn.net/"
]
}

background.js

background.js 是扩展的后台脚本,它在扩展的生命周期内持续运行,不受页面加载和卸载的影响。它通常用于处理非页面特定的逻辑,如监听浏览器事件、跨页面通信、管理扩展的状态、存储数据等。

manifest.json 文件中,background.js 通常被配置在 background 字段中

在Chrome扩展的manifest_version 3中,持久化后台脚本已被弃用,并鼓励使用事件页面(Event Pages)来替代。事件页面在需要时才被唤醒,这有助于节省系统资源。如果需要后台持续运行的功能,则需要使用服务工作者(Service Workers)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//安装时默认启用
chrome.runtime.onInstalled.addListener(() => {
chrome.storage.local.set({
Enabled: true, //启用扩展
Auto_expand: false, //自动展开
Enable_copy: true, //破解复制
Clear_doms: true, //清除弹窗
}, () => {
console.log('OK: Extension is installed!');
});
});

//监听tab页面加载,正则匹配CSDN网址
chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
if (/blog.csdn.net/.test(tab.url) && /article/.test(tab.url) && changeInfo.status === "complete") {
chrome.scripting.executeScript({
target: {
tabId: tabId
},
files: ["./content-script.js"],
}).then(() => {
console.log("INJECTED SCRIPT SUCC.");
}).catch((err) => console.log(err));
}
});

content-script.js

content-script.js是内容脚本,它会被注入到匹配的页面上下文中执行。内容脚本可以直接访问和操作页面的DOM,因此它们通常用于修改页面内容、监听用户交互、与页面JavaScript交互等。

manifest.json 文件中,content.js 通常被配置在 content_scripts 字段中,也可以在background.js中执行注入content-script.js操作。

1
{% fold secondary @展开查看完整代码 %}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
chrome.storage.local.get(['Enabled', 'Auto_expand', 'Enable_copy', 'Clear_doms'], function(value) {
if (value.Enabled) {
console.log("扩展开始执行");

if (value.Enable_copy) {
console.log("执行破解复制");
//enableCopy(); //启用复制
enableCopy2();
}

console.log("执行破解关注");
if (value.Auto_expand) {
expand(); //自动展开
} else {
modify(); //修改防止默认跳转
}

if (value.Clear_doms) {
console.log("执行清除弹窗");
removeDoms(); //移除登录弹窗等

//创建新的dom监听器
let observer = new MutationObserver((mutationsList) => {
for (let mutation of mutationsList) {
if (mutation.type == 'childList') { //只监听一级
removeDoms();
}
}
});
// 开始监听属性变化
observer.observe(document.body, {
childList: true
});
// beforeDestory(() => {
// observer.disconnect(); //取消对所有dom的监听
// observer = null;
// });
}
} else {
console.log("未启用扩展功能");
}
});

function modify() {
let follow_text = document.getElementsByClassName('follow-text');
if (follow_text.length == 0) {
return;
}
follow_text = follow_text[0];
if (follow_text.textContent == "关注博主即可阅读全文") {
follow_text.addEventListener("click", (event) => {
event.stopPropagation(); //禁止默认跳转
expand(); //展开
});
let img = document.getElementsByClassName('chevrondown')[0]; //"关注博主即可阅读全文"旁向下的箭头图标
img.addEventListener("click", (event) => {
event.stopPropagation(); //禁止默认跳转
expand(); //展开
});
follow_text.textContent = "关注限制已解锁";
console.log("关注限制已解锁");
} else {
console.log("没有找到\"关注博主即可阅读全文\"");
}
}

function expand() {
let article_content = document.getElementById("article_content");
let hide_article_box = document.getElementsByClassName('hide-article-box')[0];
article_content.removeAttribute("style");
hide_article_box.parentElement.removeChild(hide_article_box);
console.log("全文展开成功");
}

function removeDoms() {
let classes = ['passport-login-tip-container false', 'passport-login-container', 'tool-active-list', 'article-search-tip',
'hljs-button signin active', 'csdn-side-toolbar', 'box-shadow mb8', 'blog-footer-bottom'];
let infos = ['右下角弹窗', '登录弹窗', '一键收藏', '黑色提示框',
'登录复制提示', '侧边工具栏', '左侧广告', '底部备案信息'];
let boxs, box;
for (i = 0; i < classes.length; i++) {
boxs = document.getElementsByClassName(classes[i]);
if (boxs.length > 0) {
box = boxs[0];
box.parentElement.removeChild(box);
console.log("移除" + infos[i]);
}
}

let ids = ['toolbarBox', 'asideWriteGuide', 'asideNewNps', 'recommendNps'];
let names = ["顶部栏", '左侧广告', '左侧是否推荐','底部是否推荐'];
for (i = 0; i < ids.length; i++) {
box = document.getElementById(ids[i]);
if(box == null) continue;
box.parentElement.removeChild(box);
console.log("移除" + names[i]);
}
}

// 参考:https://www.cnblogs.com/pu369/p/17425742.html
function enableCopy() {
function setAllSelect(el = document.body) {
for (let index = 0; index < el.children.length; index++) {
const e = el.children.item(index);
e.style.userSelect = 'text';
setAllSelect(e);
}
}
setAllSelect();

//监听键盘Ctrl+C
document.body.onkeydown = function(e) {
if (e.ctrlKey && e.keyCode == 67) {
const pasteText = window.getSelection().toString();
if (null === pasteText || undefined === pasteText || '' === pasteText.trim()) {
return;
}
navigator.clipboard.writeText(pasteText).then(() => {
console.log("复制成功!"); //alert("复制失败!");
}).catch(() => {
console.log("复制失败!");
});
}
}
//监听右键复制无法实现
}

// 参考:https://blog.csdn.net/weixin_49119066/article/details/139220307
function enableCopy2() {
window.oncontextmenu = document.oncontextmenu = document.oncopy = null;
var hea = document.getElementsByClassName('toolbar-advert')[0];
if (hea) {
hea.remove()
};
[...document.querySelectorAll('body')].forEach(dom => dom.outerHTML = dom.outerHTML);
[...document.querySelectorAll('body, body *')].forEach(dom => {
['onselect', 'onselectstart', 'onselectend', 'ondragstart', 'ondragend', 'oncontextmenu', 'oncopy'].forEach(ev => dom.removeAttribute(ev));
dom.style['user-select'] = 'auto';
});
}
1
{% endfold %}

popup.html 通常是一个与浏览器动作(Browser Action)或页面动作(Page Action)关联的弹出窗口的HTML文件。当用户点击扩展时,将显示弹出窗口。用户可在该窗口进行相关设置。

style.css为样式表文件,用于为网页提供样式信息,控制网页的布局、颜色、字体等视觉表现

扩展中使用 popup.html,需要在 manifest.json 文件中进行配置。对于浏览器动作,需要设置 browser_action 字段,并指定 default_popup 属性为 popup.html 文件。对于页面动作,则需要设置 page_action 字段。

popup.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="./style.css">
</head>
<body>
<div align="center"><font size=3 face="黑体">CSDN插件设置</font></div>
<div class="option" align="center">
<span class="name">开启插件:</span>
<label class="switch">
<input type="checkbox" id="switch-enable" class="checkbox">
</label>
</div>
<div class="option" align="center">
<span class="name">自动展开:</span>
<label class="switch">
<input type="checkbox" id="switch-autoexpand" class="checkbox">
</label>
</div>
<div class="option" align="center">
<span class="name">破解复制:</span>
<label class="switch">
<input type="checkbox" id="switch-enablecopy" class="checkbox">
</label>
</div>
<div class="option" align="center">
<span class="name">清除弹窗:</span>
<label class="switch">
<input type="checkbox" id="switch-clearDom" class="checkbox">
</label>
</div>
<div align="center"><button id="refresh">刷新网页</button></div>
<script src="popup.js"></script>
</body>
</html>

style.css

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
html,body{
margin: 0px;
width: 200px;
height: 100px;
font-family: 'Courier New', Courier, monospace;
}

.name{
position: relative;
margin: 10px 10px 10px 10px;
}
.checkbox{
position: relative;
margin: 10px 10px 10px 10px;
}

popup.js通常与popup.html一起使用,用于处理弹出窗口(Popup)中的用户交互和动态行为。当用户点击浏览器动作(Browser Action)或页面动作(Page Action)的图标时,会打开popup.html,而popup.js则负责为其中的元素添加事件监听器、处理用户输入以及与其他部分(如背景脚本或内容脚本)进行通信。

{% fold secondary @展开查看完整代码 %}`

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
const checkBoxs = document.getElementsByClassName("checkbox");

//获取各个选项值
chrome.storage.local.get(['Enabled', 'Auto_expand', 'Enable_copy', 'Clear_doms'], function(value) {
checkBoxs[0].checked = value.Enabled;
checkBoxs[1].checked = value.Auto_expand;
checkBoxs[2].checked = value.Enable_copy;
checkBoxs[3].checked = value.Clear_doms;
});

//启用插件
checkBoxs[0].addEventListener("change", () => {
if (checkBoxs[0].checked) {
console.log("启用扩展");
chrome.storage.local.set({
Enabled: true
});
} else {
console.log("关闭扩展");
chrome.storage.local.set({
Enabled: false
});
}

//刷新网页
chrome.tabs.query({
active: true,
currentWindow: true
}, function(tabs) {
chrome.scripting.executeScript({
target: {
tabId: tabs[0].id
},
func: refreshPage,
});
});
});

//自动展开
checkBoxs[1].addEventListener("change", () => {
if (checkBoxs[1].checked) {
console.log("启用自动展开");
chrome.storage.local.set({
Auto_expand: true
});
} else {
console.log("关闭自动展开");
chrome.storage.local.set({
Auto_expand: false
});
}
});

//破解复制
checkBoxs[2].addEventListener("change", () => {
if (checkBoxs[2].checked) {
console.log("启用破解复制");
chrome.storage.local.set({
Enable_copy: true
});
} else {
console.log("关闭破解复制");
chrome.storage.local.set({
Enable_copy: false
});
}
});

//清除弹窗
checkBoxs[3].addEventListener("change", () => {
if (checkBoxs[3].checked) {
console.log("启用清除弹窗");
chrome.storage.local.set({
Clear_doms: true
});
} else {
console.log("关闭清除弹窗");
chrome.storage.local.set({
Clear_doms: false
});
}
});

document.getElementById("refresh").onclick = () => {
chrome.tabs.query({
active: true,
currentWindow: true
}, function(tabs) {
chrome.scripting.executeScript({
target: {
tabId: tabs[0].id
},
func: refreshPage,
});
});
}

function refreshPage() {
window.location.reload();
}
`{% endfold %}

分享链接

蓝奏云:https://www.lanzoub.com/iTWzE22lfbxa
密码:9dq3


Chrome浏览器扩展实践之CSDN篇(解除关注限制、破解复制)
https://blog.cngo.rr.nu/posts/716.html
作者
cngo
发布于
2024年6月24日
许可协议