知网下载助手

知网学术下载解析工具,免登录(不可用)即可下载,完全免费使用。

目前为 2025-02-28 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name 知网下载助手
  3. // @namespace cnki
  4. // @version 0.0.4
  5. // @antifeature membership
  6. // @description 知网学术下载解析工具,免登录(不可用)即可下载,完全免费使用。
  7. // @author 千千软件
  8. // @icon https://img03.mifile.cn/v1/MI_542ED8B1722DC/8a3d67192d85999be1bc1cda5c4d3528.png
  9. // @match https://*.cnki.net/kcms2/*
  10. // @require https://lib.baomitu.com/sweetalert/2.1.2/sweetalert.min.js
  11. // @require https://lib.baomitu.com/clipboard.js/2.0.6/clipboard.min.js
  12. // @run-at document-idle
  13. // @grant unsafeWindow
  14. // @grant GM_addStyle
  15. // @grant GM_getValue
  16. // @grant GM_setValue
  17. // @grant GM_deleteValue
  18. // @grant GM_listValues
  19. // @grant GM_openInTab
  20. // @grant GM_notification
  21. // @grant GM_xmlhttpRequest
  22. // @connect localhost
  23. // @connect 127.0.0.1
  24. // @connect qianqian.club
  25. // @connect cnki.net
  26. // @connect baidu.com
  27. // ==/UserScript==
  28.  
  29. (function () {
  30. 'use strict';
  31.  
  32. let globalData = {
  33. scriptVersion: '0.0.4',
  34. downloading: 0,
  35. storageNamePrefix: 'qq_storageName', // 本地储存名称前缀
  36. }
  37.  
  38. let getAppSettingData = function () {
  39. return {
  40. scriptVersion: globalData.scriptVersion,
  41. apiUrl: `/cnki.php`,
  42. storageNamePrefix: globalData.storageNamePrefix,
  43. }
  44. }
  45.  
  46. let getConfig = function () {
  47. return {
  48. code: getStorage.getLastUse('code'),
  49. }
  50. }
  51. let getStorage = {
  52. getAppConfig: (key) => {
  53. return GM_getValue(getAppSettingData().storageNamePrefix + '_app_' + key) || '';
  54. },
  55. setAppConfig: (key, value) => {
  56. GM_setValue(getAppSettingData().storageNamePrefix + '_app_' + key, value || '');
  57. },
  58. getLastUse: (key) => {
  59. return GM_getValue(getAppSettingData().storageNamePrefix + '_last_' + key) || '';
  60. },
  61. setLastUse: (key, value) => {
  62. GM_setValue(getAppSettingData().storageNamePrefix + '_last_' + key, value || '');
  63. },
  64. getCommonValue: (key) => {
  65. return GM_getValue(getAppSettingData().storageNamePrefix + '_common_' + key) || '';
  66. },
  67. setCommonValue: (key, value) => {
  68. GM_setValue(getAppSettingData().storageNamePrefix + '_common_' + key, value || '');
  69. }
  70. }
  71.  
  72. //下载面板
  73. let showDownloadDialog = function (response) {
  74. let content = `
  75. <div id="downloadDialog">
  76. <div id="dialogTop">
  77. <div id="dialogErr">${response.err}</div>
  78. </div>
  79. <div id="dialogMiddle">
  80. <div id="dialogLeft">
  81. <div id="dialogQr">
  82. <img id="dialogQrImg" src="https://img06.mifile.cn/v1/MI_542ED8B1722DC/118fd536b55197b20597d81d5974159f.jpg" />
  83. </div>
  84. </div>
  85. <div id="dialogRight">
  86. <div id="dialogContent">
  87. <div id="dialogVaptchaCode">
  88. <div id="dialogVaptchaCodeInput">
  89. <span id="dialogVaptchaCodeTips">填写验证码:</span>
  90. <input id="dialogCode" type="text" value="${getConfig().code}" />
  91. </div>
  92. <div id="dialogCodeRemark"></div>
  93. </div>
  94. <input id="dialogBtnGetUrl" type="button" value="点击继续下载" class="btnInterface" />
  95. </div>
  96. </div>
  97. </div>
  98. <div id="dialogClear"></div>
  99. <div id="dialogBottom"></div><!--众所周知的原因,脚本不可能常在,但作者常在,关注才能不迷路!!!-->
  100. </div>
  101. `;
  102. showSwal(content, {
  103. button: '关 闭',
  104. closeOnClickOutside: false
  105. });
  106. }
  107.  
  108. //请求直链成功后,tips
  109. let showQrTips = function (res) {
  110. let qrImg = $.trim(res.qrImg);
  111. let qrTips = $.trim(res.qrTips);
  112. let codeTips = $.trim(res.codeTips);
  113. let codeRemark = $.trim(res.codeRemark);
  114. //console.log(qrImg, qrTips);
  115. if (qrImg.length > 0) {
  116. $("#dialogQrImg").attr('src', qrImg);
  117. }
  118. if (qrTips.length > 0) {
  119. // $("#dialogBottom").html(qrTips);
  120. }
  121. if (codeTips.length > 0) {
  122. $("#dialogVaptchaCodeTips").html(codeTips).show();
  123. }
  124. if (codeRemark.length > 0) {
  125. $("#dialogCodeRemark").html(codeRemark).show();
  126. }
  127. }
  128.  
  129. //存储验证码
  130. let saveCode = function () {
  131. getStorage.setLastUse('code', $("#dialogCode").val());
  132. }
  133.  
  134. //=========================================
  135.  
  136. //查询接口地址-->发起服务器请求
  137. let getDownloadUrl = function (dlType) {
  138. if (globalData.downloading === 1) {
  139. return false;
  140. }
  141. setDownloadingState(dlType, '正在查询接口地址...');
  142. let bdUrl = "https://pan.baidu.com/pcloud/user/getinfo?query_uk=1070525283";
  143. let details = {
  144. method: 'GET',
  145. timeout: 10000, // 10秒超时
  146. url: bdUrl + '&' + new Date().getTime(),
  147. responseType: 'json',
  148. onload: function (res) {
  149. // console.log(res);
  150. if (res.status === 200) {
  151. if (res.response.errno == 0) {
  152. let ifDomain = res.response.user_info.intro;
  153. // console.log(ifDomain);
  154. // ifDomain = 'http://localhost:48818/cnki'
  155. getDownloadUrlReal(dlType, ifDomain);
  156. } else {
  157. throw res;
  158. }
  159. } else {
  160. throw res;
  161. }
  162. }
  163. };
  164. try {
  165. GM_xmlhttpRequest(details);
  166. } catch (error) {
  167. console.error(error);
  168. setDownloadCompleteState();
  169. showTipError('获取接口地址时报错:' + error.message)
  170. }
  171. }
  172.  
  173. let getDownloadUrlReal = function (dlType, ifDomain) {
  174. setDownloadingState(dlType, '正在请求下载地址...');
  175. let downloadUrl = `${ifDomain}${getAppSettingData().apiUrl}?version=${getAppSettingData().scriptVersion}&t=8888` + new Date().getTime();
  176. // let code = $('#dialogCode').val() || getConfig().code;
  177. let code = getConfig().code;
  178. let fileUrl = window.location.href;
  179. let fileName = $('.wx-tit h1').text();
  180. let dlUrl = $('#' + dlType + 'Down').attr('href');
  181. //官网“学位论文”栏目的bug,两个按钮的id都是cajDown,暂时就这样来修复
  182. if (!dlUrl && dlType == 'pdf') {
  183. let pdfBtn = $('li.btn-dlpdf>a').first();
  184. if (pdfBtn) {
  185. dlUrl = pdfBtn.attr('href');
  186. }
  187. }
  188.  
  189. let params = new FormData();
  190. params.append('code', $.trim(code));
  191. params.append('fileUrl', fileUrl);
  192. params.append('fileName', fileName);
  193. params.append('dlUrl', dlUrl);
  194. params.append('dlType', dlType);
  195. //远程请求下载地址
  196. let details = {
  197. method: 'POST',
  198. responseType: 'json',
  199. timeout: 30000, // 30秒超时
  200. url: downloadUrl,
  201. data: params,
  202. onload: function (res) {
  203. // params.forEach((value, key) => {
  204. // console.log("%s --> %s", key, value);
  205. // })
  206. setDownloadCompleteState();
  207. console.log('远程请求直链地址,返回:', res);
  208. if (res.status === 200) {
  209. switch (res.response.errno) {
  210. case 0: // 正常返回
  211. console.log('正常返回');
  212. downFile(res.response.downloadUrl);
  213. break;
  214. case 100: // 版本太旧
  215. showTipErrorSwal(res.response.err);
  216. break;
  217. case 101: // 验证码不正确
  218. showDownloadDialog(res.response);
  219. showQrTips(res.response);
  220. //绑定按钮点击(点击继续下载)
  221. $("#dialogBtnGetUrl").click(function () {
  222. saveCode();
  223. swal.close();
  224. getDownloadUrl();
  225. });
  226. break;
  227. default: // 其它错误
  228. showTipError(res.response.err);
  229. break;
  230. }
  231. } else {
  232. console.error(res);
  233. showTipError('请求下载地址失败!服务器返回:' + res.status);
  234. }
  235. },
  236. ontimeout: (res) => {
  237. console.error(res);
  238. setDownloadCompleteState();
  239. showTipError('请求下载地址时连接服务器接口超时,请重试!');
  240. },
  241. onerror: (res) => {
  242. console.error(res);
  243. setDownloadCompleteState();
  244. showTipError('请求下载地址时连接服务器接口出错,请重试!');
  245. }
  246. };
  247. try {
  248. GM_xmlhttpRequest(details);
  249. } catch (error) {
  250. showTipError('远程请求未知错误,请重试!');
  251. setDownloadCompleteState();
  252. console.error(error);
  253. }
  254. }
  255.  
  256. let setDownloadingState = function (dlType, tips) {
  257. globalData.downloading = 1;
  258. $('#' + dlType + 'BtnName').text(tips);
  259. }
  260. let setDownloadCompleteState = function () {
  261. globalData.downloading = 0;
  262. $('#pdfBtnName').text('知网助手下载PDF');
  263. $('#cajBtnName').text('知网助手下载CAJ');
  264. }
  265.  
  266. let showTipErrorSwal = function (err) {
  267. showSwal(err, {icon: 'error'});
  268. }
  269.  
  270. let showSwal = function (content, option) {
  271. divTips.innerHTML = content;
  272. option.content = divTips;
  273. if (!option.hasOwnProperty('button')) {
  274. option.button = '朕 知 道 了'
  275. }
  276. swal(option);
  277. }
  278.  
  279. let showTipError = function (err) {
  280. // showSwal(err,{icon: 'error'});
  281. alert(err);
  282. }
  283.  
  284. //========================================= 公共函数
  285.  
  286. let downFile = function (url) {
  287. const a = document.createElement('a');
  288. a.style.display = 'none';
  289. a.href = url;
  290. document.body.appendChild(a);
  291. a.click();
  292. document.body.removeChild(a);
  293. };
  294.  
  295. // 延迟执行,否则找不到对应的按钮
  296. let sleep = function (time) {
  297. return new Promise((resolve) => setTimeout(resolve, time));
  298. };
  299.  
  300. //========================================= css
  301. GM_addStyle(`
  302. .operate-btn .btn-dl-helper a {
  303. background-color: #ff6988
  304. }
  305. .operate-btn .btn-dl-helper a:hover {
  306. background-color: #dd2014
  307. }
  308. .operate-btn .btn-dlpdf-helper i {
  309. background-position: -75px 0
  310. }
  311. .operate-btn .btn-dlcaj-helper i {
  312. background-position: -50px 0
  313. }
  314. .operate-btn li .btn-dl-helper i {
  315. display: inline-block;
  316. vertical-align: middle;
  317. width: 25px;
  318. height: 25px;
  319. background-image: url(https://piccache.cnki.net/nxgp/kcms/2023121114r/images/gb/kcms8/ndetail/icon-dllinkbtns3.png);
  320. background-repeat: no-repeat;
  321. *height: 20px;
  322. }
  323. .operate-left {
  324. padding-right: 0px;
  325. }
  326. a.aDownHelper {
  327. font-size: 16px;
  328. font-weight: bold;
  329. }
  330. /****************************************/
  331. .swal-modal {
  332. width: auto;
  333. min-width: 730px;
  334. }
  335. .swal-modal input {
  336. border: 1px grey solid;
  337. }
  338. #downloadDialog{
  339. width: 730px;
  340. font-size: 16px;
  341. }
  342.  
  343. #dialogTop{
  344. margin: 20px 0;
  345. }
  346. #dialogErr{
  347. background: #f4c758;
  348. margin: 15px -20px 0 -20px;
  349. padding: 10px 0 10px 25px;
  350. color: #4c4433;
  351. }
  352. #dialogLeftTips{
  353. text-align: left;
  354. margin: 0 0 10px 0px;
  355. color: #4c4433;
  356. font-size: 13px;
  357. }
  358. #dialogRight{
  359. width: 56%;
  360. float: left;
  361. margin-left: 10px;
  362. }
  363. #dialogContent input{
  364. vertical-align: middle;
  365. }
  366. #dialogRemark{
  367. text-align: left;
  368. font-size: 12px;
  369. margin-top: 5px;
  370. }
  371. #dialogVaptchaCode{
  372. text-align: left;
  373. font-size: 14px;
  374. /* border: 2px solid #EDD; */
  375. line-height: 28px;
  376. }
  377. #dialogVaptchaCodeInput{
  378. font-size: 18px;
  379. }
  380. #dialogCode{
  381. width: 65%;
  382. font-size: 18px;
  383. padding: 3px;
  384. }
  385. #dialogCodeRemark{
  386. margin: 10px 0px;
  387. padding: 3px;
  388. }
  389. #dialogQr{
  390. width: 265px;
  391. height: 265px;
  392. text-align: center;
  393. }
  394. #dialogQr img{
  395. width: 100%;
  396. margin-left: 27px;
  397. }
  398. #dialogClear{
  399. clear: both;
  400. }
  401. #dialogBottom{
  402. text-align: left;
  403. margin: 20px -20px -5px -20px;
  404. background: #f4c758;
  405. color: #4c4433;
  406. height: 1px;
  407. }
  408. .btnInterface {
  409. width: 100%;
  410. height: 50px;
  411. background: #f00 !important;
  412. border-radius: 4px;
  413. transition: .3s;
  414. font-size: 25px !important;
  415. border: 0;
  416. color: #fff;
  417. cursor: pointer;
  418. text-decoration: none;
  419. font-family: Microsoft YaHei,SimHei,Tahoma;
  420. font-weight: 100;
  421. letter-spacing: 2px;
  422. }
  423. #dialogLeft{
  424. float: left;
  425. width: 42%;
  426. }
  427. .swal-footer{
  428. margin-top: 5px;
  429. }
  430. .div-dl-helper{
  431. margin-bottom: 10px;
  432. text-align: center;
  433. }
  434. `);
  435. // ==================================== 逻辑代码开始
  436. console.log('脚本开始');
  437.  
  438. const divTips = document.createElement('div');
  439. divTips.id = "divTips";//用于提示脚本版本
  440.  
  441. let btnDownload = {
  442. id: 'divCnkiHelper',
  443. html: function () {
  444. return `
  445. <li id="liPdfBtn" title="使用知网下载助手进行下载" class="btn-dl-helper btn-dlpdf-helper" style="margin-right: 5px;">
  446. <a id="pdfDownHelper" class="aDownHelper" href="#">
  447. <i></i>
  448. <text id="pdfBtnName"></text>
  449. </a>
  450. </li>
  451. <li id="liCajBtn" title="使用知网下载助手进行下载" class="btn-dl-helper btn-dlcaj-helper">
  452. <a id="cajDownHelper" class="aDownHelper" href="#">
  453. <i></i>
  454. <text id="cajBtnName"></text>
  455. </a>
  456. </li>
  457. `
  458. },
  459. class: function () {
  460. return 'div-dl-helper';
  461. }
  462. }
  463.  
  464. let start = function () {//迭代调用
  465. if (!$('#pdfDown')[0]) {
  466. if (!$('li.btn-dlpdf>a').first()) {
  467. //官网“学位论文”栏目的bug,两个按钮的id都是cajDown,暂时就这样来修复
  468. console.log('找不到【PDF下载】按钮,该文档不可下载!');
  469. return;
  470. }
  471. }
  472. if (!$('#cajDown')[0]) {
  473. console.log('找不到【CAJ下载】按钮!');
  474. // return;
  475. }
  476. let operateBtn = $('ul.operate-btn');
  477.  
  478. // 创建按钮 START
  479. let divCnkiHelper = document.createElement('div');
  480. divCnkiHelper.id = btnDownload.id;
  481. divCnkiHelper.innerHTML = btnDownload.html();
  482. // divCnkiHelper.style.cssText = btnDownload.style();
  483. divCnkiHelper.className = btnDownload.class();
  484. // 创建按钮 END
  485.  
  486. // 添加按钮 START
  487. operateBtn.children().first().before(divCnkiHelper);
  488. if (!$('#cajDown')[0]) $('#liCajBtn').hide();//如果无caj下载按钮
  489. setDownloadCompleteState();
  490. // 添加按钮 END
  491.  
  492. //绑定点击事件
  493. $('.aDownHelper').click(function (e) {
  494. let dlType = $(this).attr('id').slice(0, 3);
  495. console.log('#' + dlType + 'DownHelper 点击事件');
  496. e.preventDefault();
  497. // getDownloadUrlReal();
  498. getDownloadUrl(dlType);
  499. });
  500. }
  501.  
  502. sleep(500).then(() => {
  503. start();
  504. // GM_deleteValue('qq_storageName_last_code');//测试
  505. })
  506. })();
  507. //#################

QingJ © 2025

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