Greasy Fork镜像 支持简体中文。

豆瓣小组清新空气计划

抓取用户豆瓣黑名单,在后台存储并自动屏蔽黑名单用户的帖子

目前為 2024-10-24 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name 豆瓣小组清新空气计划
  3. // @version 0.0.2
  4. // @license MIT
  5. // @namespace https://gf.qytechs.cn/users/1384897
  6. // @description 抓取用户豆瓣黑名单,在后台存储并自动屏蔽黑名单用户的帖子
  7. // @author ✌
  8. // @match https://www.douban.com/group/*
  9. // @grant GM_setValue
  10. // @grant GM_getValue
  11. // ==/UserScript==
  12. (function() {
  13. const utils = {
  14. // 通过 Tampermonkey 后台保存配置
  15. saveConfig: config => {
  16. GM_setValue('douban_group_enhance_config', config);
  17. console.log('保存黑名单到后台: ', config);
  18. },
  19. // 从 Tampermonkey 后台获取配置
  20. getConfig: () => {
  21. const config = GM_getValue('douban_group_enhance_config', { blackUserList: [] });
  22. console.log('从后台加载黑名单: ', config);
  23. return config;
  24. }
  25. }
  26.  
  27. // 手动抓取豆瓣黑名单
  28. const fetchBlacklist = async () => {
  29. let start = 0;
  30. let userIdList = [];
  31. let hasNextPage = true;
  32.  
  33. console.log('开始抓取豆瓣黑名单...');
  34.  
  35. while (hasNextPage) {
  36. const url = `https://www.douban.com/contacts/blacklist?start=${start}`;
  37. console.log('请求黑名单页面: ', url);
  38.  
  39. const response = await fetch(url, {
  40. credentials: 'include' // 保持登录(不可用)状态
  41. });
  42.  
  43. if (response.ok) {
  44. console.log('黑名单页面响应成功,解析中...');
  45. const text = await response.text();
  46. const parser = new DOMParser();
  47. const doc = parser.parseFromString(text, 'text/html');
  48.  
  49. // 从页面中提取用户ID
  50. const userLinks = doc.querySelectorAll('dl.obu dd a');
  51.  
  52. if (userLinks.length === 0) {
  53. console.log('没有找到更多用户,终止抓取。');
  54. break; // 没有更多用户数据,终止抓取
  55. }
  56.  
  57. userLinks.forEach(link => {
  58. const userProfileUrl = link.getAttribute('href');
  59. const userId = userProfileUrl.split('/').filter(v => v).pop(); // 提取user_id
  60. userIdList.push(userId);
  61. console.log('抓取到用户ID: ', userId);
  62. });
  63.  
  64. // 检查是否还有下一页
  65. hasNextPage = !!doc.querySelector('.next');
  66. start += 72; // 下一页的起始值增加
  67. console.log('是否有下一页: ', hasNextPage);
  68. } else {
  69. console.error('请求黑名单页面失败: ', response.status);
  70. hasNextPage = false; // 请求失败则终止抓取
  71. }
  72. }
  73.  
  74. console.log('黑名单抓取完成: ', userIdList);
  75. return userIdList;
  76. }
  77.  
  78. // 更新黑名单配置
  79. const updateBlacklistConfig = async () => {
  80. console.log('手动更新黑名单配置...');
  81. const blackUserIds = await fetchBlacklist();
  82. const config = { blackUserList: blackUserIds };
  83.  
  84. utils.saveConfig(config); // 保存配置到 Tampermonkey 后台
  85. console.log("黑名单用户ID已更新: ", blackUserIds);
  86. }
  87.  
  88. // 屏蔽用户功能
  89. const runFiltUser = (config) => {
  90. console.log('开始运行屏蔽用户功能...');
  91. $('.olt tr td:nth-child(2) a').each(function() {
  92. const $this = $(this);
  93. const userProfileUrl = $this.attr('href'); // 获取用户个人主页链接
  94. const userId = userProfileUrl.split('/').filter(v => v).pop(); // 提取用户ID
  95. const isBlackUser = id => (config.blackUserList || []).includes(id); // 使用ID判断是否在黑名单
  96. if (isBlackUser(userId)) {
  97. console.log("屏蔽首页发帖:", userId);
  98. $this.parents('tr').hide(); // 隐藏发帖行
  99. }
  100. });
  101. }
  102.  
  103. // 帖子内屏蔽黑名单用户
  104. const runFilterBlackUser = (config, self) => {
  105. const userProfileUrl = self.find('h4 a').attr('href'); // 获取发帖用户的个人主页链接
  106. const userId = userProfileUrl.split('/').filter(v => v).pop(); // 提取user_id
  107. const isBlackUser = id => (config.blackUserList || []).includes(id);
  108. if (isBlackUser(userId)) {
  109. console.log("屏蔽回帖人: ", userId);
  110. self.hide(); // 隐藏发帖
  111. return;
  112. }
  113.  
  114. const isFiltBeReplyedUser = config.filtBeReplyedBlackUser;
  115. if (isFiltBeReplyedUser) {
  116. const replyQuote = self.find('.reply-quote');
  117. if (replyQuote != null) {
  118. const replyProfileUrl = replyQuote.find('.reply-quote-content .pubdate a').attr('href');
  119. const replyUserId = replyProfileUrl.split('/').filter(v => v).pop(); // 回复的用户ID
  120. if (isBlackUser(replyUserId)) {
  121. console.log("屏蔽回复: ", replyUserId);
  122. self.hide(); // 隐藏回复
  123. return;
  124. }
  125. }
  126. }
  127. }
  128.  
  129. const addButtonToPage = () => {
  130. const buttonHtml = `
  131. <button id="updateBlacklistButton" style="position:fixed; bottom:20px; left:20px; padding:12px 20px; background-color:#409EFF; color:#fff; border:none; border-radius:5px; box-shadow:0 4px 8px rgba(0,0,0,0.1); font-size:14px; cursor:pointer; transition:background-color 0.3s ease;">
  132. 更新黑名单
  133. </button>
  134. <div id="balloon" style="display:none; position:fixed; bottom:90px; left:20px; transform:translateX(10px); font-size:30px; letter-spacing:-5px; text-align:center;">
  135. 🎈🎈🎈
  136. </div>
  137. `;
  138. $('body').append(buttonHtml);
  139.  
  140. $('#updateBlacklistButton').hover(
  141. function() {
  142. $('#balloon').css('display', 'block').css('opacity', '1');
  143. },
  144. function() {
  145. $('#balloon').css('opacity', '0');
  146. setTimeout(() => {
  147. $('#balloon').css('display', 'none');
  148. }, 300);
  149. }
  150. );
  151.  
  152. // 点击按钮时更新黑名单
  153. $('#updateBlacklistButton').click(async () => {
  154. $('#updateBlacklistButton').text('更新中...');
  155. await updateBlacklistConfig();
  156. $('#updateBlacklistButton').text('更新黑名单');
  157. });
  158. }
  159.  
  160. // 脚本初始化
  161. const init = () => {
  162. console.log('初始化增强脚本...');
  163. const config = utils.getConfig(); // 从后台获取黑名单配置
  164. runFiltUser(config); // 屏蔽首页用户
  165. $('#comments li').each(function() {
  166. const $this = $(this);
  167. runFilterBlackUser(config, $this); // 屏蔽帖子内用户
  168. });
  169. }
  170.  
  171. addButtonToPage();
  172.  
  173. init();
  174. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址