知乎热榜首页显示回答数、关注数、浏览数、创建者、创建时间

在知乎的热榜页中,显示每个问题的回答数、关注数、浏览数、创建者、创建时间。

  1. // ==UserScript==
  2. // @name 知乎热榜首页显示回答数、关注数、浏览数、创建者、创建时间
  3. // @namespace http://tampermonkey.net/
  4. // @version 2024-03-05
  5. // @description 在知乎的热榜页中,显示每个问题的回答数、关注数、浏览数、创建者、创建时间。
  6. // @author Fat Cabbage
  7. // @license MIT
  8. // @match https://www.zhihu.com/hot
  9. // @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
  10. // @grant GM_setValue
  11. // @grant GM_getValue
  12. // @require https://code.jquery.com/jquery-3.5.1.min.js
  13. // ==/UserScript==
  14. /* globals jQuery, $, waitForKeyElements */
  15.  
  16. let question_status_list = {};
  17.  
  18. (function () {
  19. 'use strict';
  20.  
  21. let wrapper_node_list = document.getElementsByClassName('HotItem-metrics');
  22. let links_list = document.getElementsByClassName('HotItem-content');
  23.  
  24. (async () => {
  25. for (let i = 0; i < links_list.length; i++) {
  26. let links = links_list[i].getElementsByTagName('a')
  27. let href = links[0].href;
  28.  
  29. if (/question/.test(href)) {
  30. let log_href = `${href}/log`
  31.  
  32. let match = href.match(/.*\/question\/(\d+)/)
  33. let id = match ? match[1] : -1;
  34.  
  35. if (question_status_list[id] == null) {
  36. question_status_list[id] = {};
  37. }
  38. question_status_list[id].wrapper_node = wrapper_node_list[i];
  39. question_status_list[id].updated = true;
  40.  
  41. let config = GM_getValue(id, {});
  42.  
  43. if (config.last_updated != null) {
  44. let time_diff = new Date() - new Date(config.last_updated);
  45. time_diff /= 1000 * 60;
  46.  
  47. if (config.followers == null || config.views == null || config.answers == null || time_diff > 5) {
  48. console.log("time_diff", time_diff);
  49. console.log("知乎热榜首页显示回答数 case1");
  50. await fetchDataRow1(href, id);
  51. }
  52. } else {
  53. console.log("知乎热榜首页显示回答数 case2");
  54. await fetchDataRow1(href, id);
  55. }
  56.  
  57. if (config.author == null || config.time == null) {
  58. await fetchDataRow2(log_href, id);
  59. }
  60.  
  61. update_interface_value();
  62. }
  63. }
  64. })();
  65. })();
  66.  
  67. function fetchDataRow1(href, id) {
  68. return new Promise(function (resolve) {
  69. $.get(href, function (res) {
  70. let dom = new DOMParser().parseFromString(res, 'text/html');
  71. let values = dom.getElementsByClassName('NumberBoard-itemValue');
  72.  
  73. let followers_num = parseInt(values[0].outerText.replaceAll(',', ''));
  74. let views_num = parseInt(values[1].outerText.replaceAll(',', ''));
  75.  
  76. values = dom.getElementsByClassName('List-headerText');
  77. let answer_num = values[0].outerText;
  78. answer_num = answer_num.replaceAll(' 个回答', '').replaceAll(',', '')
  79. answer_num = parseInt(answer_num);
  80.  
  81. let config = GM_getValue(id, {});
  82.  
  83. config.followers = followers_num;
  84. config.views = views_num;
  85. config.answers = answer_num;
  86. config.last_updated = new Date().toISOString();
  87.  
  88. GM_setValue(id, config);
  89.  
  90. if (question_status_list[id] == null) {
  91. question_status_list[id] = {};
  92. }
  93.  
  94. question_status_list[id].updated = true;
  95.  
  96. update_interface_value();
  97.  
  98. resolve(res);
  99. });
  100. });
  101. }
  102.  
  103. function fetchDataRow2(href, id) {
  104. return new Promise(function (resolve) {
  105. $.get(href, function (res) {
  106. let dom = new DOMParser().parseFromString(res, 'text/html');
  107. let log_list = dom.getElementsByClassName('zm-item');
  108. let initial_log = log_list[log_list.length - 1];
  109.  
  110. let child1 = initial_log.children[0];
  111. let author = child1.outerText;
  112. author = author.replaceAll('添加了问题', '').replaceAll('\n', '');
  113.  
  114. let child2 = initial_log.querySelector('time');
  115. let time = child2.outerText;
  116.  
  117. let config = GM_getValue(id, {});
  118.  
  119. config.author = author;
  120. config.time = time;
  121.  
  122. GM_setValue(id, config);
  123.  
  124. if (question_status_list[id] == null) {
  125. question_status_list[id] = {};
  126. }
  127.  
  128. question_status_list[id].updated = true;
  129.  
  130. update_interface_value();
  131.  
  132. resolve(res);
  133. });
  134. });
  135. }
  136.  
  137. function update_interface_value() {
  138. for (let id in question_status_list) {
  139.  
  140. let node = question_status_list[id].wrapper_node;
  141. let updated = question_status_list[id].updated;
  142.  
  143. let config = GM_getValue(id);
  144. let followers_num = config.followers;
  145. let views_num = config.views;
  146. let answer_num = config.answers;
  147. let author = config.author;
  148. let created_time = config.time;
  149.  
  150. let last_updated = '';
  151. if (config.last_updated != null) {
  152. let time_diff = new Date() - new Date(config.last_updated);
  153. time_diff /= 1000 * 60;
  154.  
  155. if (time_diff > 1) {
  156. time_diff = Math.round(time_diff);
  157. last_updated = `(${time_diff}分钟前更新)`;
  158. } else {
  159. last_updated = "(刚刚更新)";
  160. }
  161. }
  162.  
  163.  
  164. if (!updated) {
  165. continue;
  166. }
  167.  
  168. node = node.childNodes;
  169.  
  170. let view_str;
  171. if (views_num < 1e4) {
  172. view_str = `${views_num} `;
  173. } else if (views_num < 1e8) {
  174. view_str = `${Math.floor(views_num / 1e4)} 万`;
  175. } else {
  176. view_str = `${(views_num / 1e8).toFixed(1)} 亿`;
  177. }
  178.  
  179. let match = node[1].nodeValue.match(/\d+.*?热度/);
  180. let hot = match ? match[0] : -1;
  181.  
  182. let row1_text = `${hot} - ${answer_num} 回答 - ${followers_num} 关注 - ${view_str}浏览${last_updated}`
  183. let row1_node = document.createTextNode(row1_text);
  184.  
  185. for (let i = 1; i < node.length - 1; i++) {
  186. node[i].remove();
  187. }
  188. node[0].parentNode.style.bottom = '5px'
  189. node[0].parentNode.style.zIndex = '1'
  190. node[0].parentNode.insertBefore(row1_node, node[1])
  191.  
  192. if (author != null) {
  193. let br = document.createElement('br');
  194. let row2_text = `创建 ${author} | ${created_time}`
  195. let row2_node = document.createTextNode(row2_text);
  196.  
  197. node[0].parentNode.insertBefore(br, node[2]);
  198. node[0].parentNode.insertBefore(row2_node, node[3])
  199. }
  200.  
  201. config.updated = false;
  202. }
  203. }

QingJ © 2025

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