文库下载器

百度文库、淘豆网、豆丁网、道客巴巴、原创力文档解析下载功能 解除百度文库、淘豆网复制限制【保持原格式】界面简洁,脚本仅限学习,请大家支持正版。

  1. // ==UserScript==
  2. // @name 文库下载器
  3. // @version 1.5.0
  4. // @namespace https://waahah.gitee.io
  5. // @description 百度文库、淘豆网、豆丁网、道客巴巴、原创力文档解析下载功能 解除百度文库、淘豆网复制限制【保持原格式】界面简洁,脚本仅限学习,请大家支持正版。
  6. // @author waahah
  7. // @antifeature membership 百度文库需要输入验证码之后才能下载,淘豆网及豆丁网和道客巴巴等可直接导出PDF
  8. // @require https://cdn.bootcss.com/jquery/3.5.1/jquery.min.js
  9. // @require https://cdn.staticfile.org/jspdf/2.5.1/jspdf.umd.min.js
  10. // @require https://cdn.staticfile.org/html2canvas/1.4.1/html2canvas.min.js
  11. // @match *://wenku.baidu.com/view/*
  12. // @match *://wenku.baidu.com/tfview/*
  13. // @match *://wenku.baidu.com/link?url*
  14. // @match *://wenku.baidu.com/share/*
  15. // @match *://www.doc88.com/p-*
  16. // @match *://www.docin.com/p-*
  17. // @match *://jz.docin.com/p-*
  18. // @match *://www.taodocs.com/p-*
  19. // @match *://file.taodocs.com/p-*
  20. // @match *://max.book118.com/html/*
  21. // @license Apache-2.0
  22. // @icon data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cpath fill='none' d='M0 0h24v24H0z'/%3E%3Cpath d='M13 13v5.585l1.828-1.828 1.415 1.415L12 22.414l-4.243-4.242 1.415-1.415L11 18.585V13h2zM12 2a7.001 7.001 0 0 1 6.954 6.194 5.5 5.5 0 0 1-.953 10.784v-2.014a3.5 3.5 0 1 0-1.112-6.91 5 5 0 1 0-9.777 0 3.5 3.5 0 0 0-1.292 6.88l.18.03v2.014a5.5 5.5 0 0 1-.954-10.784A7 7 0 0 1 12 2z'/%3E%3C/svg%3E
  23. // @grant unsafeWindow
  24. // @grant GM_openInTab
  25. // @grant GM.openInTab
  26. // @grant GM_getValue
  27. // @grant GM.getValue
  28. // @grant GM_setValue
  29. // @grant GM.setValue
  30. // @grant GM_xmlhttpRequest
  31. // @grant GM.xmlHttpRequest
  32. // @grant GM_registerMenuCommand
  33. // ==/UserScript==
  34.  
  35. (function () {
  36. /**
  37. * 遵循开源协议,转载请注明出处谢谢
  38. */
  39. 'use strict';
  40.  
  41. $(function () {
  42.  
  43. let webUrl = window.location.href;
  44. let webUrl2;
  45. const path = window.location.pathname.split("/")[1];
  46. const host = location.host;
  47. const tfpath = location.href.split("/");
  48. const title = document.title.split(' - ')[0];
  49. const InterfaceList = [
  50. { "host": "wkdownload", "url": "http://www.mmhtml.com/zh/?url=" },
  51. { "host": "wenku.baidu.com", "func": "bdwk()", "el": "bdwk_ele" },
  52. { "host": "www.doc88.com", "func": "doc()", "el": "doc_ele" },
  53. { "host": "www.docin.com", "func": "docin()", "el": "docin_ele" },
  54. { "host": "jz.docin.com", "func": "docin()", "el": "docin_ele" },
  55. { "host": "www.taodocs.com", "func": "taodou()", "el": "taodou_ele" },
  56. { "host": "file.taodocs.com", "func": "taodou()", "el": "taodou_ele" },
  57. { "host": "max.book118.com", "func": "book118()", "el": "book118_ele" }
  58. ]
  59. function GMxmlhttpRequest(obj) {
  60. if (typeof GM_xmlhttpRequest === "function") {
  61. GM_xmlhttpRequest(obj);
  62. }
  63. else { GM.xmlhttpRequest(obj); }
  64. }
  65. function GMopenInTab(url, open_in_background) {
  66. if (typeof GM_openInTab === "function") {
  67. GM_openInTab(url, open_in_background);
  68. }
  69. else { GM.openInTab(url, open_in_background); }
  70. }
  71. const after = obj => {
  72. return obj.replace('/view/', '/share/').replace('.html', '') + '?share_api=1&width=800';
  73. }
  74. const css = css => {
  75. const myStyle = document.createElement('style');
  76. myStyle.textContent = css;
  77. const doc = document.head || document.documentElement;
  78. doc.appendChild(myStyle);
  79. }
  80.  
  81. css(`#zuihuitao {cursor:pointer; position:fixed; top:100px; left:0px; width:0px; z-index:2147483647; font-size:12px; text-align:left;}
  82. #zuihuitao .logo { position: absolute;right: 0; width: 1.375rem;padding: 10px 2px;text-align: center;color: #fff;cursor: auto;user-select: none;border-radius: 0 4px 4px 0;transform: translate3d(100%, 5%, 0);background: deepskyblue;}
  83. #zuihuitao .die {display:none; position:absolute; left:28px; top:0; text-align:center;background-color:#04B4AE; border:1px solid gray;}
  84. #zuihuitao .die li{font-size:12px; color:#fff; text-align:center; width:60px; line-height:21px; float:left; border:1px solid gray;border-radius: 6px 6px 6px 6px; padding:0 4px; margin:4px 2px;list-style-type: none;}
  85. #zuihuitao .die li:hover{color:#fff;background:#FE2E64;}
  86. @media print {body {display: block !important;}}
  87. *{-webkit-user-select: text; -moz-user-select: text; -ms-user-select: text; user-select: text;}
  88. .add{background-color:#FE2E64;}
  89. .btn-success{position: fixed;font-weight: 400;color: #fff;background-color: #28a745;border-color: #28a745;text-align: center;vertical-align: middle;border: 1px solid transparent;padding: .375rem .75rem;font-size: 1rem;line-height: 1.5;border-radius: .25rem; z-index:2147483647;cursor: pointer;}`);
  90.  
  91.  
  92. const html = $(`<div id='zuihuitao'>
  93. <div class='item_text'>
  94. <div class="logo"><a id="m">文库下载</a></div>
  95. <div class='die' >
  96. <div style='display:flex;'>
  97. <div style='width:128px; padding:0px 0;'>
  98. <br>
  99. <div style='font-size:16px; text-align:center; color:#fff; line-height:21px;'>bdwk解析</div>
  100. <ul style='margin:0 24px;'>
  101. <li id="li0">下载</li>
  102. <div style='clear:both;'></div>
  103. </ul>
  104. <br>
  105. <div style='font-size:16px; text-align:center; color:#fff; line-height:21px;'>其它文库</div>
  106. <ul style='margin:0 25px;'>
  107. <li id="li2">导出PDF</li>
  108. <li id="li3">自动展开</li>
  109. <div style='clear:both;'></div>
  110. </ul>
  111. <br>
  112. </div>`);
  113.  
  114. webUrl2 = after(webUrl);
  115. $("body").append(html);
  116. $(".item_text").on("mouseover", () => {
  117. $(".die").show();
  118. });
  119. $(".item_text").on("mouseout", () => {
  120. $(".die").hide();
  121. });
  122. console.log(document.lastModified);
  123.  
  124. if (path == "link") {
  125. const base_url = "https://wenku.baidu.com/user/interface/layerpop?act=get&platform=pc&layer_id=8";
  126. const xhttp = new XMLHttpRequest();
  127. xhttp.open("GET", base_url);
  128. xhttp.send(null);
  129. xhttp.onreadystatechange = function () {
  130. if (this.readyState == 4 && this.status == 200) {
  131. console.log('success');
  132. let datas = xhttp.responseText;
  133. //console.log(xhttp.responseText);
  134. datas = JSON.parse(datas);
  135. console.log(datas);
  136. const have = datas.data[8].data.pageInfo;
  137. if (have !== undefined) {
  138. const url = have.referer;
  139. console.log(url);
  140. webUrl = url;
  141. webUrl2 = after(url);
  142. } else {
  143. console.log('用户已登录(不可用)账号 url为空,使用方案二');
  144. const pageData = document.querySelector("body > script:nth-child(5)").innerText;
  145. //console.log(pageData);
  146. const DocId = pageData.indexOf('showDocId') + 12;
  147. const StoreId = pageData.indexOf('showStoreId') - 3;
  148. const showDocId = pageData.slice(DocId, StoreId);
  149. const url = tfpath[0] + "//" + tfpath[2] + '/view/' + showDocId + ".html";
  150. console.log(url);
  151. webUrl = url;
  152. webUrl2 = after(url);
  153. }
  154.  
  155. }
  156. }
  157. }
  158. if (path == "tfview") {
  159. const tfurl = tfpath[0] + "//" + tfpath[2] + "/view/" + tfpath[4];
  160. const tfurl2 = after(tfurl);
  161. console.log(tfurl);
  162. webUrl = tfurl;
  163. webUrl2 = tfurl2;
  164. }
  165.  
  166. const sleep = ms => {
  167. return new Promise(resolve => setTimeout(resolve, ms));
  168. }
  169.  
  170. const taodou_zhankai = () => {
  171. if (host == InterfaceList[5].host) {
  172. if (typeof inpmv != undefined) {
  173. let btn = document.querySelector('.moreBtn.goBtn span');
  174. if (btn) {
  175. btn.click();
  176. }
  177. }
  178. }
  179. }
  180.  
  181. const share = () => {
  182. //console.log(webUrl);
  183. let FPS = 1000;
  184. let retime = setInterval(function () {
  185. let ph = document.body.scrollHeight;
  186. $(window).scrollTop(FPS, { behavior: 'smooth' });
  187. //ph = document.body.scrollHeight;
  188. FPS = FPS + 1000;
  189. taodou_zhankai();
  190. if (FPS > ph) {
  191. clearInterval(retime);
  192. /*setTimeout(function () {
  193. window.print();
  194. $(".logo").show();
  195. }, 500);
  196. */
  197. }
  198. }, 500)
  199.  
  200. }
  201.  
  202. const downloadPDF = (canvas, pdfName) => {
  203. /*
  204. window.scrollTo(0, 0);
  205. let eleW = ele.offsetWidth; // 获得该容器的宽
  206. let eleH = ele.offsetHeight; // 获得该容器的高
  207. let eleOffsetTop = ele.offsetTop; // 获得该容器到文档顶部的距离
  208. let eleOffsetLeft = ele.offsetLeft; // 获得该容器到文档最左的距离
  209.  
  210. var canvas = document.createElement("canvas");
  211. var abs = 0;
  212.  
  213. let win_in = document.documentElement.clientWidth || document.body.clientWidth; // 获得当前可视窗口的宽度(不包含滚动条)
  214. let win_out = window.innerWidth; // 获得当前窗口的宽度(包含滚动条)
  215.  
  216. if (win_out > win_in) {
  217. // abs = (win_o - win_i)/2; // 获得滚动条长度的一半
  218. abs = (win_out - win_in) / 2; // 获得滚动条宽度的一半
  219. // console.log(a, '新abs');
  220. }
  221. canvas.width = eleW * 2; // 将画布宽&&高放大两倍
  222. canvas.height = eleH * 2;
  223.  
  224. var context = canvas.getContext("2d");
  225. context.scale(2, 2);
  226. context.translate(-eleOffsetLeft - abs, -eleOffsetTop);
  227. // 这里默认横向没有滚动条的情况,因为offset.left(),有无滚动条的时候存在差值,因此
  228. // translate 的时候,要把这个差值去掉
  229.  
  230. html2canvas(ele, {
  231. dpi: 300,
  232. scale: 1,
  233. allowTaint: false, //允许 canvas 污染, allowTaint参数要去掉,否则是无法通过toDataURL导出canvas数据的
  234. useCORS: true, //允许canvas画布内 可以跨域请求外部链接图片, 允许跨域请求。
  235. }).then((canvas) => {
  236. var contentWidth = canvas.width;
  237. var contentHeight = canvas.height;
  238. //一页pdf显示html页面生成的canvas高度;
  239. var pageHeight = contentWidth / 595.28 * 841.89;
  240. //未生成pdf的html页面高度
  241. var leftHeight = contentHeight;
  242. //页面偏移
  243. var position = 0;
  244. //a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
  245. var imgWidth = 595.28;
  246. var imgHeight = 595.28 / contentWidth * contentHeight;
  247. var pageData = canvas.toDataURL('image/jpeg', 1.0);
  248. var pdf = new jspdf.jsPDF('', 'pt', 'a4');
  249. //有两个高度需要区分,一个是html页面的实际高度,和生成pdf的页面高度(841.89)
  250. //当内容未超过pdf一页显示的范围,无需分页
  251. // console.log('处理完画布高度:' + contentHeight)
  252. // console.log('每页高度:' + pageHeight)
  253. // console.log(imgWidth, imgHeight);
  254.  
  255. if (leftHeight < pageHeight) {
  256. //在pdf.addImage(pageData, 'JPEG', 左,上,宽度,高度)设置在pdf中显示;
  257. pdf.addImage(pageData, 'JPEG', 0, 0, imgWidth, imgHeight);
  258. } else { // 分页
  259. while (leftHeight > 10) {
  260. // console.log(leftHeight)
  261. pdf.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight);
  262. leftHeight -= pageHeight;
  263. position -= 871.89;
  264. //避免添加空白页
  265. if (leftHeight > 10) {
  266. pdf.addPage();
  267. }
  268. }
  269. }
  270. //可动态生成
  271. pdf.save(pdfName)
  272. })*/
  273. window.scrollTo(0, 0);
  274. let num = 0;
  275. let err_num = 0;
  276. let len_cas = canvas.length;
  277. var contentWidth = canvas[0].width;
  278. var contentHeight = canvas[0].height;
  279. //console.log(canvas);
  280. console.log(`canvas数据:宽: ${contentWidth}px,高: ${contentHeight}px`);
  281.  
  282. const orientation = contentWidth > contentHeight ? 'l' : 'p';
  283. var pdf = new jspdf.jsPDF(orientation, 'px', [contentHeight, contentWidth]);
  284. for (const cas of canvas) {
  285. let pageData = cas;
  286. num += 1;
  287. try{
  288. pdf.addImage(pageData, 'JPEG', 0, 0, contentWidth, contentHeight);
  289. }catch(err){
  290. console.log(err);
  291. err_num += 1;
  292. //continue;
  293. }
  294. if (num < len_cas) {
  295. pdf.addPage();
  296. }
  297. }
  298.  
  299. pdf.save(`${pdfName}.pdf`);
  300. if(err_num){
  301. alert(`有 ${err_num} 页未加载!`);
  302. }
  303. }
  304.  
  305. const clipboardCopy = text => {
  306. if (navigator.clipboard) {
  307. navigator.clipboard.writeText(text);
  308. } else {
  309. const textarea = document.createElement('textarea');
  310. document.body.appendChild(textarea);
  311. textarea.style.position = 'fixed';
  312. textarea.style.clip = 'rect(0 0 0 0)';
  313. textarea.style.top = '10px';
  314. textarea.value = text;
  315. textarea.select();
  316. document.execCommand('copy', true);
  317. document.body.removeChild(textarea);
  318. }
  319. }
  320.  
  321. const replica = (selectText = true) => {
  322. /**
  323. * 灵感来源于https://gf.qytechs.cn/zh-CN/scripts/445128
  324. */
  325.  
  326. try {
  327. if (host == InterfaceList[1].host) {
  328. let text = $('div.link')[0].outerText.split("”的文档")[0].split("查看全部包含“")[1];
  329. clipboardCopy(text);
  330. $('.dialog-mask').remove();
  331. $('.copy-limit-dialog-v2').remove();
  332. } else if (host == InterfaceList[5].host) {
  333. $('.sel_tips').remove();
  334. let selectedText = window.getSelection().toString();
  335. if (selectedText == '') {
  336. clipboardCopy(selectText);
  337. } else {
  338. clipboardCopy(selectedText);
  339. }
  340. }
  341. } catch (error) {
  342. console.log(error.stack)
  343. text = "出错啦,请通知作者修复";
  344. throw new Error(`Error: ${error}`);
  345. }
  346.  
  347. }
  348.  
  349. (() => {
  350. let oldtext = "";
  351. let count = 0;
  352. if (host == InterfaceList[1].host || host == InterfaceList[5].host) {
  353. $(document).unbind('keydown').bind('keydown', e => {
  354. if (e.ctrlKey && e.keyCode == 67) {
  355. replica();
  356. $(".btn-success").text("复制成功").fadeOut(1000);
  357. e.preventDefault();
  358. count += 1;
  359. //return false;
  360. }
  361. })
  362.  
  363. document.onmouseup = ev => {
  364. let nowtext;
  365. $(".btn-success").remove();
  366. if (host == InterfaceList[1].host) {
  367. nowtext = $('div.link')[0].outerText.split("”的文档")[0].split("查看全部包含“")[1];
  368. } else if (host == InterfaceList[5].host) {
  369. let selectedText = window.getSelection().toString();
  370. if (selectedText) {
  371. nowtext = selectedText;
  372. }
  373. }
  374.  
  375. if (nowtext != oldtext) {
  376. const oEvent = ev || event;
  377. const elbtn = $(`<div class="btn-success" style="left:${oEvent.clientX + 15 + 'px'}; top: ${oEvent.clientY - 10 + 'px'};">复制</div>`);
  378. $("body").append(elbtn);
  379. oldtext = nowtext;
  380. $("#reader-helper").hide();
  381. }
  382.  
  383. $(".btn-success").on("click", e => {
  384. replica(nowtext);
  385. count += 1;
  386. console.info(`第${count}次为您复制,内容为:${nowtext}`);
  387. //$(".btn-success").fadeOut(1000);
  388. }).on("mouseup", e => {
  389. $(".btn-success").text("复制成功");
  390. $(".btn-success").fadeOut(1000);
  391. e.stopPropagation();
  392. e.preventDefault();
  393. })
  394. }
  395. }
  396. })();
  397.  
  398. const del = el => {
  399. $(el).remove();
  400. }
  401.  
  402. const bdwk_ele = ['.read-all', '.header-wrapper', '.no-full-screen', '.no-full-screen', '.lazy-load',
  403. '.reader-topbar', '.content-wrapper+div', '.hx-warp', '.try-end-fold-page',
  404. '#page-footer', '#reader-container+div', '#passport-login-pop'
  405. ]
  406. const doc_ele = ['#continueButton', '#header', '#toolbar', '#box1', '#boxright', '#readEndDiv', '.commonbox1',
  407. '#commentDiv', '.clearfix', '#footer', '.dk-bg', '.toplayer-shop', '.activelist'
  408. ]
  409. const docin_ele = ['.model-fold-show', '.page_crubms clear', '.doc_header_mod', '.aside', '#j_isend',
  410. '#docinShareSlider', '.backToTop', '.reader_tools_bar_wrap.tools_bar_small.clear',
  411. '.page_crubms.clear', '.adBox', '#jControlDiv'
  412. ]
  413. const taodou_ele = ['span.fc2e', '.sel_tips']
  414. const book118_ele = ['#btn_preview_remain']
  415.  
  416. const bdwk = () => {
  417. $(".logo").hide();
  418. $(".die").hide();
  419. share();
  420. setTimeout(() => {
  421. window.print();
  422. $(".logo").show();
  423. }, 1000);
  424. }
  425.  
  426. const doc = () => {
  427. const ele = document.querySelectorAll('canvas.inner_page');
  428. try {
  429. downloadPDF(ele, title);
  430. } catch (error) {
  431. //TODO handle the exception
  432. console.log(error.stack);
  433. }
  434. }
  435.  
  436. const docin = () => {
  437. const ele = document.querySelectorAll('canvas');
  438. try {
  439. downloadPDF(ele, title);
  440.  
  441. } catch (error) {
  442. console.log(error.message);
  443. }
  444. }
  445.  
  446. const taodou = () => {
  447. let ele = document.querySelectorAll('.textLayer_div canvas');
  448. if (ele.length == 0) {
  449. ele = document.querySelectorAll('img.errorimg');
  450. if (ele.length == 0) {
  451. ele = document.querySelectorAll('img');
  452. }
  453. }
  454. try {
  455. downloadPDF(ele, title);
  456.  
  457. } catch (error) {
  458. console.log(error.message);
  459. }
  460. }
  461.  
  462. const book118 = () => {
  463. const ele = document.querySelectorAll('.webpreview-item img');
  464. try {
  465. downloadPDF(ele, title);
  466.  
  467. } catch (error) {
  468. console.log(error);
  469. }
  470. }
  471.  
  472. const main = () => {
  473. for (const even in InterfaceList) {
  474. if (host == InterfaceList[even].host) {
  475. let ee = InterfaceList[even].el;
  476. $(eval(ee)[0]).click();
  477. for (const el of eval(ee)) {
  478. del(el);
  479. }
  480. eval(InterfaceList[even].func);
  481. break;
  482. }
  483. }
  484. }
  485.  
  486. $("#li0").bind("click", e => {
  487. if (host == InterfaceList[1].host) {
  488. window.open(InterfaceList[0].url + webUrl);
  489. } else {
  490. e.preventDefault();
  491. alert('百度文库解析,其它文库请使用导出PDF');
  492. }
  493. });
  494. $("#li2").bind("click", () => {
  495. if (confirm('请确保每一页都加载完再打印,是否打印?')) {
  496. main();
  497. }
  498. });
  499. $("#li3").on("click", () => {
  500. for (const even in InterfaceList) {
  501. if (host == InterfaceList[even].host) {
  502. let ee = InterfaceList[even].el;
  503. $(eval(ee)[0]).click();
  504. break;
  505. }
  506. }
  507. $('.die').hide();
  508. share();
  509. });
  510.  
  511. });
  512.  
  513. })();

QingJ © 2025

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