Wenku Doc Downloader

下载“百度文库”“豆丁网”文档,仅支持导出为txt文档或图片型的pdf。

当前为 2021-11-26 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Wenku Doc Downloader
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.5
  5. // @description 下载“百度文库”“豆丁网”文档,仅支持导出为txt文档或图片型的pdf。
  6. // @author allenlv2690@gmail.com
  7. // @match https://wenku.baidu.com/view/*
  8. // @match https://www.docin.com/p-*
  9. // @icon https://www.google.com/s2/favicons?domain=limestart.cn
  10. // @grant none
  11. // @license GPL-3.0-only
  12. // @create 2021-11-22
  13. // @note 修复了“pdf元素数量>2,doc元素数量=1”时不能下载文档的bug
  14. // @note 特此感谢“chmdir”的反馈
  15. // @note 【图片下载合并器】没有更新
  16. // ==/UserScript==
  17.  
  18. /*
  19. * 附属功能函数部分
  20. */
  21.  
  22. function createAndDownloadFile(fileName, content) {
  23. // 创建并下载文件
  24. var aTag = document.createElement('a');
  25. var blob = new Blob([content]);
  26. aTag.download = fileName;
  27. aTag.href = URL.createObjectURL(blob);
  28. aTag.click();
  29. URL.revokeObjectURL(blob);
  30. }
  31.  
  32. function formatText(text){
  33. // 用于纯文本文档的文本美化
  34. var reg_exp_1 = new RegExp(" [(]?=[\u4e00-\u9fa5] [)]");
  35. var reg_exp_2 = new RegExp("(?<=TEMP[\u4e00-\u9fa5]) ");
  36. var reg_exp_3 = new RegExp("(?<=[\u4e00-\u9fa5]) (?=[\u4e00-\u9fa5])");
  37.  
  38. var text_1 = text.replace(reg_exp_1, "TEMP");
  39. var text_2 = text_1.replace(reg_exp_2, "");
  40. var text_3 = text_2.replace("TEMP", "");
  41. var text_final = text_3.replace(/ /g, " ");
  42. return text_final;
  43. }
  44.  
  45. function formatText2(text) {
  46. // 用于图形文字混合型文档的文本美化
  47. var reg_exp = new RegExp("[  ]{2,}");
  48. var content_1 = text.replace(reg_exp, "\n");
  49.  
  50. var content_2 = content_1.replace(/[  ]\n/g, "\n");
  51.  
  52. var reg_exp_2 = new RegExp("\n[   ]*\n*\n");
  53. var content_3 = content_2.replace(reg_exp_2, "\n");
  54.  
  55. var reg_exp_3 = new RegExp(" *\n * ");
  56. var content_4 = content_3.replace(reg_exp_3, "\n");
  57.  
  58. var content_5 = content_4.replace(/[  ]/g, " ");
  59. var final_content = content_5.replace(/[ \n]精选文档[ \n]/g).replace(/\n{2,}/g, "\n");
  60.  
  61. return final_content;
  62. }
  63.  
  64. /*
  65. * 主要功能函数部分
  66. */
  67.  
  68. function readAll() {
  69. var read_all_btn = document.getElementsByClassName("read-all")[0];
  70. // 如果存在“继续阅读”的按钮
  71. if (read_all_btn) {
  72. // 点击“继续阅读”按钮
  73. read_all_btn.click();
  74. }
  75. // 如果点击完之后仍旧存在该按钮,递归调用自身
  76. // read_all_btn = document.getElementsByClassName("read-all")[0];
  77. // if (read_all_btn) {
  78. // readAll();
  79. // }
  80. else{
  81. alert("文档已经完全展开,可以导出");
  82. var init_btn = document.getElementsByClassName("init-btn")[0];
  83. var save_doc_btn = document.getElementsByClassName("save-doc-btn")[0];
  84. init_btn.style.display = "none";
  85. save_doc_btn.style.removeProperty("display");
  86. }
  87. }
  88.  
  89. function savePDFData() {
  90. // 存储pdf型data(假定是内容是pic)
  91. alert("Function savePDFData was called.");
  92. var pic_urls = document.getElementsByClassName("reader-pic-item");
  93. var text_list = [];
  94. // 去掉前缀
  95. var reg_exp_1 = new RegExp(": ?url[(]");
  96. // 去掉后缀
  97. var reg_exp_2 = new RegExp("[)]; ?background-position");
  98.  
  99. for (var i = 0; i < pic_urls.length; i++){
  100. var whole_text = pic_urls[i].getAttribute("style");
  101. var de_pretext = whole_text.split(reg_exp_1)[1];
  102. var url = de_pretext.split(reg_exp_2)[0];
  103. text_list.push(url);
  104. }
  105.  
  106. text_list[0] = text_list[0].replace(/"/g, "");
  107. var content = text_list.join("\n");
  108. createAndDownloadFile("urls.csv", content);
  109. }
  110.  
  111. function saveDocData() {
  112. // 存储doc型data(内容是text)
  113. alert("Function saveDocData was called.");
  114. // 获取文本
  115. var text_elements = document.getElementsByClassName("reader-word-layer");
  116. var texts = [];
  117. for (var elem of text_elements){
  118. texts.push(elem.textContent);
  119. }
  120. // 美化后导出文本
  121. var origin_content = texts.join("");
  122. var content = formatText(origin_content);
  123. createAndDownloadFile("纯文本文档.txt", content);
  124. }
  125.  
  126. function savePPTData() {
  127. // 存储ppt型data(内容是pic)
  128. alert("Function savePPTData was called.");
  129. var pic_elements = document.getElementsByClassName("ppt-image-wrap");
  130. var pic_urls = [];
  131.  
  132. for (var elem of pic_elements) {
  133. var pic_obj = elem.children[0];
  134. var url = pic_obj.src;
  135. pic_urls.push(url);
  136. }
  137.  
  138. var content = pic_urls.join("\n");
  139. createAndDownloadFile("urls.csv", content);
  140. }
  141.  
  142. function saveExcelData() {
  143. // 1. 拿到表格
  144. var table_pic = document.getElementsByClassName("reader-pic-item")[0];
  145. var url = table_pic.style.getPropertyValue("background-image");
  146. // 获取图片地址
  147. var pure_url = url.slice(5, -2);
  148.  
  149. // 2. 拿到表格内文字信息
  150. var text_elems = document.getElementsByClassName("reader-word-layer");
  151. var text_list = [];
  152. for (var elem of text_elems) {
  153. text_list.push(elem.textContent);
  154. }
  155. var _text = text_list.join("\n");
  156. // 替换奇怪的空格
  157. var text = _text.replace(/ /g, " ");
  158.  
  159. // 3. 合并至一个字符串,然后导出
  160. var head = "表格图形链接如下(复制到浏览器中打开):";
  161. var content = head + "\n\n" + pure_url + "\n\n" + text;
  162. createAndDownloadFile("图片地址和表格内容.txt", content);
  163. }
  164.  
  165. function saveDocAndPicData() {
  166. // 对于文字和图形混合型的data只能存储其中的纯文字
  167. alert("Function saveDocAndPicData was called.");
  168. // 获取文本
  169. var text_elements = document.getElementsByClassName("reader-word-layer");
  170. var texts = [];
  171. for (var elem of text_elements){
  172. texts.push(elem.textContent);
  173. }
  174. // 处理文本中的过长空格
  175. var origin_content = texts.join("");
  176. // 美化后导出文本
  177. var content = formatText2(origin_content);
  178. createAndDownloadFile("纯文本文档.txt", content);
  179. }
  180.  
  181. function savePdfWithTitleData() {
  182. // 这是带有文字标题行的pdf文档,将直接忽略其中的标题行
  183. savePDFData();
  184. }
  185.  
  186. function detectType() {
  187. // 分别尝试获取相应元素列表,若列表长度为0则不存在相应元素,否则存在
  188. var pdf = document.getElementsByClassName("reader-pic-item").length;
  189. var doc = document.getElementsByClassName("reader-word-layer").length;
  190. var ppt = document.getElementsByClassName("ppt-image-wrap").length;
  191. // 判断文档类别
  192. if (pdf && !doc && !ppt) {
  193. return "pdf";
  194. }
  195. else if (doc && !pdf && !ppt) {
  196. return "doc";
  197. }
  198. else if (ppt && !pdf && !doc) {
  199. return "ppt";
  200. }
  201. else if (pdf === 1 && doc > 1 && !ppt) {
  202. return "excel";
  203. }
  204. else if (pdf > 2 && doc > 2 && !ppt) {
  205. return "docANDpic";
  206. }
  207. else if (pdf > 2 && doc === 1 && !ppt) {
  208. return "pdfWithTitle"
  209. }
  210. else {
  211. return {"pdf元素数量": pdf, "doc元素数量": doc, "ppt元素数量": ppt};
  212. }
  213. }
  214.  
  215. function saveData() {
  216. // 存储文档数据到本地
  217. var category = detectType();
  218. if (category === "pdf"){
  219. savePDFData();
  220. }
  221. else if (category === "doc") {
  222. saveDocData();
  223. }
  224. else if (category === "ppt") {
  225. savePPTData();
  226. }
  227. else if (category === "excel") {
  228. saveExcelData();
  229. }
  230. else if (category === "docANDpic") {
  231. saveDocAndPicData();
  232. }
  233. else if (category === "pdfWithTitle") {
  234. savePdfWithTitleData();
  235. }
  236. else {
  237. var info = [];
  238. for (var key in category){
  239. info.push(key + " : " + category[key]);
  240. }
  241. alert("未知文档类型\n" + info.join("\n"));
  242. }
  243. }
  244.  
  245. /*
  246. * 主函数部分
  247. */
  248.  
  249. function baiduWenku() {
  250. // 创建脚本启动按钮1、2
  251. var btn_1 = document.createElement("button");
  252. var btn_2 = document.createElement("button");
  253. // 设定按钮1、2样式
  254. btn_1.setAttribute("class", "init-btn");
  255. btn_1.style.height = "25px";
  256. btn_1.style.width = "50%";
  257. btn_1.style.marginLeft = "25%";
  258. btn_1.style.backgroundColor = "blue";
  259.  
  260. btn_2.setAttribute("class", "save-doc-btn");
  261. btn_2.style.height = "25px";
  262. btn_2.style.width = "50%";
  263. btn_2.style.marginLeft = "25%";
  264. btn_2.style.backgroundColor = "green";
  265. btn_2.style.display = "none";
  266.  
  267. // 绑定主函数
  268. btn_1.addEventListener("click", readAll);
  269. btn_2.addEventListener("click", saveData);
  270. // 添加按钮元素到页面
  271. document.body.appendChild(btn_1);
  272. document.body.appendChild(btn_2);
  273. // 确认主程序加载完毕
  274. console.log("Program Loaded");
  275. }
  276.  
  277. function docin() {
  278. // 创建脚本启动按钮
  279. var btn = document.createElement("button");
  280. // 设定按钮1、2样式
  281. btn.style.height = "25px";
  282. btn.style.width = "50%";
  283. btn.style.marginLeft = "25%";
  284. btn.style.backgroundColor = "green";
  285.  
  286. // 绑定主函数
  287. var printPage = function() {window.print();};
  288. btn.addEventListener("click", printPage);
  289. // 添加按钮元素到页面
  290. document.body.appendChild(btn);
  291. // 确认主程序加载完毕
  292. console.log("Program Loaded");
  293. }
  294.  
  295. function main() {
  296. var host = window.location.host;
  297. if (host === "wenku.baidu.com") {
  298. baiduWenku();
  299. }
  300. else if (host === "www.docin.com") {
  301. docin();
  302. }
  303. else {
  304. console.log("匹配到了无效网页");
  305. }
  306. }
  307.  
  308. main();