// ==UserScript== // @name 中国知网CNKI硕博论文PDF下载 // @version 3.0 // @namespace https://greasyfork.org/users/244539 // @icon https://www.cnki.net/favicon.ico // @description 知网文献、硕博论文PDF批量下载,下载论文章节目录,阅读页面体验增强 // @author 爱与自由 // @match http*://*.cnki.net // @match http*://*/kcms/detail/detail.aspx?*dbcode=* // @match http*://*/*/*/kcms/detail/detail.aspx?*dbcode=* // @match http*://*/*/*/kcms/detail* // @match http*://*/https/*/kcms* // @match http*://*/KCMS/detail/detail.aspx?*dbcode=* // @match http*://*/kns*/defaultresult/index* // @match http*://*/https/*/kns8/defaultresult/index // @match http*://*/https/*/kns8/DefaultResult/Index* // @match http*://*/kns8s/DefaultResult/Index // @match http*://*/https/*/kcms/detail/detail.aspx? // @match http*://*/KNS8/AdvSearch?* // @match http*://*/kns8/AdvSearch?* // @match http*://kns.cnki.net/kns8s/AdvSearch?crossids* // @match http*://kns.cnki.net/kns8s/AdvSearch?classid* // @match http*://kns.cnki.net/kns/advsearch?dbcode* // @match http*://*.*.*.*:*/kns8s/search // @match http*://*/kns/brief/*result* // @match http*://*/kcms/Detail/DownDetail.aspx* // @match http*://*/KNS8/DefaultResult/index* // @match http*://*/kns8/DefaultResult/Index* // @match http*://*/kns8/defaultresult/index* // @match http*://*/https/*/KNS8/DefaultResult/* // @match http*://*/kcms2/article/abstract?* // @match *://kns.cnki.net/KXReader/Detail?* // @match *://new.oversea.cnki.net/KXReader/Detail?* // @match *://new.big5.oversea.cnki.net/KXReader/Detail?* // @match *://new.gb.oversea.cnki.net/KXReader/Detail?* // @match *://*/KXReader/Detail?* // @run-at document-idle // @grant unsafeWindow // @grant GM_getValue // @grant GM_setValue // @grant GM_xmlhttpRequest // @license MIT // @downloadURL none // ==/UserScript== (function() { 'use strict'; const $ = unsafeWindow.jQuery; function loadCss(code) { const style = document.createElement('style'); style.textContent = code; document.head.appendChild(style); } function createLoading(text, duration) { const loadingContent = document.createElement('div'); loadingContent.style.cssText = 'position:fixed;top:50%;left:50%;transform:translate(-50%, -50%);text-align:center;color:#333;font-size:16px;width:400px;height:40px;line-height:40px;z-index:9999;border:1px solid #0f5de5;padding:5px;background-color:#fff'; loadingContent.textContent = text; document.body.appendChild(loadingContent); setTimeout(() => document.body.removeChild(loadingContent), duration); return loadingContent; } function createPopupButton() { const popupButton = document.createElement('button'); popupButton.textContent = '批量下载PDF'; popupButton.style.cssText = 'position:fixed;right:50px;top:50%;transform:translateY(-50%);z-index:9999;padding:10px;background-color:#0f5de5;color:#fff;border:none;cursor:pointer;border-radius:5px;'; popupButton.addEventListener('click', createPopup); document.body.appendChild(popupButton); } function createPopup() { if (document.getElementById('popup')) return; const popup = document.createElement('div'); popup.id = 'popup'; popup.style.cssText = 'position:fixed;top:0;left:0;width:100%;height:100%;background-color:rgba(0,0,0,0.5);z-index:9999;'; const content = document.createElement('div'); content.style.cssText = 'position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);width:80%;max-height:80%;overflow-y:auto;background-color:#fff;padding:20px;border-radius:10px;box-shadow:0 0 10px rgba(0,0,0,0.5);min-height:200px'; const closeButton = createButton('关闭', () => document.body.removeChild(popup)); closeButton.style.float = 'right'; const linkButton = createButton('获取链接', getLinks); const selectAllButton = createButton('全选', selectAll); const deselectAllButton = createButton('取消全选', deselectAll); const downloadButton = createButton('下载', downloadSelected); downloadButton.title = "点击此处下载选中的文件"; downloadButton.id = "dl_sel"; const tooltip = document.getElementById('tooltip'); function showTooltip(e) { tooltip.style.display = 'block'; tooltip.style.left = e.pageX + 10 + 'px'; tooltip.style.top = e.pageY + 10 + 'px'; } function hideTooltip() { tooltip.style.display = 'none'; } downloadButton.addEventListener('mouseenter', showTooltip); downloadButton.addEventListener('mousemove', showTooltip); downloadButton.addEventListener('mouseleave', hideTooltip); // const selectCount = document.createElement('span'); // selectCount.textContent = '已选择: 0'; // selectCount.className = 'diy-btn'; const tips = createTips('获取链接后请不要关闭窗口,否则链接会消失!', 'red'); const tips2 = createTips('如果获取失败或超时,请关闭窗口重新获取。', '#0b1f64'); content.append(closeButton, linkButton, selectAllButton, deselectAllButton, downloadButton, tips, tips2); const table = document.createElement('table'); table.id = 'my-table'; table.style.cssText = 'width:100%;margin-top:10px;border-collapse:collapse;'; table.innerHTML = '多选序号名称链接关键词'; content.appendChild(table); popup.appendChild(content); document.body.appendChild(popup); } function createButton(text, onClick) { const button = document.createElement('button'); button.textContent = text; button.className = 'diy-btn'; button.addEventListener('click', onClick); return button; } function createTips(text, color) { const tips = document.createElement('span'); tips.textContent = text; tips.className = 'diy-btn'; tips.style.color = color; return tips; } function selectAll() { document.querySelectorAll('.selectItem').forEach(item => item.checked = true); updateSelectCount(); } function deselectAll() { document.querySelectorAll('.selectItem').forEach(item => item.checked = false); updateSelectCount(); } function downloadSelected() { const selectedItems = document.querySelectorAll('.selectItem:checked'); if (selectedItems.length === 0) { createLoading('请选择要下载的项目!', 2000); return; } selectedItems.forEach(item => { const link = item.closest('tr').querySelector('a[href^="http"]'); if (link) { window.open(link.href); }; }); } function updateSelectCount() { const count = document.querySelectorAll('.selectItem:checked').length; document.querySelector('#dl_sel').textContent = `下载 (${count})`; } async function getLinks() { const table = document.querySelector('#my-table tbody'); if (table.children.length > 0) { createLoading('已有数据!关闭弹窗后打开可重新获取!', 2000); return; } const links = Array.from(document.querySelectorAll('.fz14')).map(link => link.href); const loading = createLoading('获取链接中(请耐心等待)……', 60000); try { const batchSize = 5; // 每批处理的链接数 for (let i = 0; i < links.length; i += batchSize) { const batch = links.slice(i, i + batchSize); const responses = await Promise.all(batch.map(link => fetch(link, { method: 'GET', mode: 'same-origin', referrerPolicy: 'unsafe-url', }).then(response => response.text()) )); responses.forEach((html, index) => { const doc = new DOMParser().parseFromString(html, 'text/html'); const title = doc.querySelector('.wx-tit')?.firstElementChild?.textContent || '无标题'; const author = Array.from(doc.querySelectorAll('.author')).map(a => a.textContent).join(' '); const pdfLink = doc.querySelector('#pdfDown')?.href || '无链接'; const keywords = Array.from(doc.querySelectorAll('.keywords a')).map(keywords => `${keywords.textContent.replace(";","")}`).join(''); const row = table.insertRow(); row.innerHTML = ` ${i + index + 1} ${title}${author} ${pdfLink !== '无链接' ? `PDF下载` : '获取链接失败!'} ${keywords} `; row.querySelector('input[type="checkbox"]').addEventListener('change', updateSelectCount); }); // 更新加载提示 loading.textContent = `正在获取链接...(${Math.min((i + batchSize) / links.length * 100, 100).toFixed(0)}%)`; } document.body.removeChild(loading); createLoading('获取完毕!', 2000); } catch (error) { console.error('Error fetching links:', error); document.body.removeChild(loading); createLoading(`获取链接出错:${error.message}`, 3000); } } // 目录下载功能 function addCategoryDownloadButton() { const otherBtns = document.querySelector('.other-btns'); if (!otherBtns) return; const li = document.createElement('li'); li.className = 'btn-diy'; li.style.cssText = 'width:auto;height:23px;line-height:22px;background-color:#3f8af0;border-radius:3px;'; const a = document.createElement('a'); a.textContent = '目录下载'; a.className = 'a-diy'; a.style.cssText = 'color:#ffffff;padding:2px 10px;'; a.href = 'javascript:void(0)'; a.addEventListener('click', downloadCategory); li.appendChild(a); otherBtns.appendChild(li); } async function downloadCategory() { const hrefLink = document.querySelector('.operate-btn li:nth-child(4) a')?.href; if (!hrefLink) { createLoading('无法获取目录链接', 2000); return; } try { const response = await fetch(hrefLink); const html = await response.text(); const doc = new DOMParser().parseFromString(html, 'text/html'); const title = doc.querySelector('.title')?.textContent || '未知标题'; const chapters = Array.from(doc.querySelectorAll('.ls-chapters li')) .map(chapter => chapter.textContent.trim()) .filter(Boolean) .map(text => { const parts = text.split('-'); return `${parts[0].replace(/\n/g, '\t')} \n`; }) .join(''); console.log(chapters); saveFile(title, chapters); } catch (error) { console.error('Error downloading category:', error); createLoading('下载目录失败', 2000); } } function saveFile(name, data) { const blob = new Blob([data], { type: 'text/plain' }); const link = document.createElement('a'); link.href = URL.createObjectURL(blob); link.download = `${name}.txt`; link.click(); URL.revokeObjectURL(link.href); } // 阅读模式调整功能 function addReadingModeAdjustment() { const backtop = document.querySelector('.backtop'); if (!backtop) return; const fontSizeIncrease = createReadingModeButton('增大字体', '字✚', () => changeFontSize('increase')); fontSizeIncrease.style.bottom = '-60px'; const fontSizeDecrease = createReadingModeButton('减小字体', '字━', () => changeFontSize('decrease')); fontSizeDecrease.style.bottom = '-30px'; const protectEyesSelect = document.createElement('select'); protectEyesSelect.innerHTML = ` `; protectEyesSelect.style.cssText = 'width:36px;font-size:12px;'; protectEyesSelect.id = 'protect_eyes_select'; protectEyesSelect.addEventListener('change', function() { changeMode(this.value); }); backtop.append(protectEyesSelect, fontSizeIncrease, fontSizeDecrease); changeModeAuto(); } function createReadingModeButton(title, text, action) { const button = document.createElement('span'); button.title = title; button.textContent = text; button.className = 'font-size-button'; button.addEventListener('click', action); return button; } function changeFontSize(action) { const main = document.querySelector('.main'); if (!main) return; const currentSize = parseFloat(window.getComputedStyle(main).fontSize); const newSize = action === 'increase' ? currentSize + 1 : currentSize - 1; main.style.fontSize = `${newSize}px`; main.querySelectorAll('.p1').forEach(p => p.style.fontSize = `${newSize}px`); } function changeMode(color) { localStorage.bgc = color; document.body.style.backgroundColor = color; document.querySelectorAll('.ecp_top-nav, .content, .tips, .main, .refer, .brief').forEach(el => el.style.backgroundColor = color); document.querySelectorAll('dl, p').forEach(el => el.style.backgroundColor = color); } function changeModeAuto() { if (localStorage.bgc) { changeMode(localStorage.bgc); const select = document.getElementById('protect_eyes_select'); if (select) { const option = Array.from(select.options).find(option => option.value === localStorage.bgc); if (option) option.selected = true; } } } // 初始化函数 function init() { const url = window.location.href.toLowerCase(); console.log(url); // 在所有页面上添加批量下载按钮 // createPopupButton(); if (url.includes('defaultresult') || url.includes('advsearch')) { createPopupButton(); } // 在文献详情页面添加目录下载按钮和阅读模式调整功能 if (url.includes('abstract') || url.includes('detail.aspx') || url.includes('detail') || url.includes('read')) { addCategoryDownloadButton(); addReadingModeAdjustment(); } // 加载自定义CSS loadCss(` .diy-btn { display: inline-block; vertical-align: middle; padding: 2px 8px; margin-left: 5px; line-height: 18px; color: #0f5de5; font-size: 14px; text-align: center; background-color: #e3ecfd; border: 1px solid #fff; cursor: pointer; } #popup table tr td, #popup table tr th { line-height: 20px; height: 20px; padding: 5px; border: 1px solid #eee; } .diy_title { display: block; color: #524d4d; font-size: 14px; font-weight: bold; } .diy_author { color: #666; } .font-size-button { font-size: 14px; display: block; line-height: 18px; border: 1px solid #e2e2e2; border-radius: 2px; background-color: #f5f5f5; color: #504f4f; float: left; padding: 3px; position: absolute; right: 0; width: 28px; cursor: pointer; } `); } // 在页面加载完成后运行初始化函数 // 在页面加载完成后运行初始化函数 window.addEventListener('load', init); })();