知网-文献-bibtex提取
// ==UserScript==
// @name 知网-文献-bibtex提取
// @namespace https://github.com/BNDou/getCnkiLiteratureBibTex
// @description 从知网文献中直接复制引文,支持多种引文格式:BibTeX、GB/T 7714-2015、知网研学、CAJ-CD、MLA、APA、Refworks、EndNote、NoteExpress、NodeFirst
// @license AGPL License
// @version 4.2.1
// @author BN_Dou
// @match *://kns.cnki.net/kcms2/article/abstract*
// @match *://kns.cnki.net/kcms/detail*
// @match *://kns.cnki.net/kns8s/defaultresult/index*
// @match *://kns.cnki.net/kns8s/search*
// @match *://kns.cnki.net/kns8s/AdvSearch*
// @grant GM_registerMenuCommand
// @grant GM_setClipboard
// @grant GM_getValue
// @grant GM_setValue
// @icon https://www.cnki.net/favicon.ico
// ==/UserScript==
(function () {
'use strict';
// 引文类型定义
const CITATION_TYPES = {
'BibTeX': 'BibTex',
'GB/T 7714-2015': 'GBTREFER',
'知网研学': 'elearning',
'CAJ-CD': 'REFER',
'MLA': 'MLA',
'APA': 'APA',
'Refworks': 'Refworks',
'EndNote': 'EndNote',
'NoteExpress': 'NoteExpress',
'NodeFirst': 'NodeFirst'
};
// 获取当前引文类型
let currentCitationType = GM_getValue('citationType', 'BibTeX');
// 更新按钮文本
function updateButtonText() {
// 更新普通按钮
const buttons = document.querySelectorAll('[id^="bibbtn"]');
buttons.forEach(button => {
if (button.querySelector('span')) {
button.querySelector('span').textContent = currentCitationType;
}
});
// 更新批量复制按钮
const batchLink = document.querySelector('#batch_bibbtn_li a');
if (batchLink) {
batchLink.textContent = `批量复制${currentCitationType}`;
}
}
// 更新菜单项
function updateMenuItems() {
// 添加菜单项
for (const [typeName, _] of Object.entries(CITATION_TYPES)) {
GM_registerMenuCommand(`🔄 切换到 ${typeName}`, () => switchCitationType(typeName));
}
}
// 切换引文类型
function switchCitationType(type) {
currentCitationType = type;
GM_setValue('citationType', type);
updateButtonText();
}
// 样式定义
const STYLES = {
button: `
width: 65px;
height: 25px;
border-radius: 12px;
background-color: #0f5de5;
border: none;
color: white;
font-size: 12px;
font-weight: 600;
text-align: center;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 2px 8px rgba(15, 93, 229, 0.3);
display: flex;
align-items: center;
justify-content: center;
gap: 4px;
position: relative;
z-index: 1;
`,
advSearchButton: `
width: 100%;
height: 24px;
padding: 0 8px;
border-radius: 8px;
background-color: #f0f0f0;
border: 1px solid #ddd;
color: #0f5de5;
font-size: 12px;
font-weight: normal;
text-align: center;
cursor: pointer;
transition: all 0.2s ease;
margin: 4px 0;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 2px;
`,
successAnimation: `
@keyframes successPulse {
0% { transform: scale(1); }
50% { transform: scale(1.1); }
100% { transform: scale(1); }
}
`
};
let citationText = '';
// 创建并注入样式
function injectStyles() {
const styleSheet = document.createElement('style');
styleSheet.textContent = STYLES.successAnimation;
document.head.appendChild(styleSheet);
}
// 创建按钮
function createButton(isAdvSearch = false) {
const button = document.createElement('button');
button.id = "bibbtn";
button.title = "点击复制引文";
button.innerHTML = `<span>${currentCitationType}</span>`;
button.style.cssText = isAdvSearch ? STYLES.advSearchButton : STYLES.button;
if (isAdvSearch) {
// 高级检索页面的悬停效果
button.addEventListener('mouseover', () => {
button.style.backgroundColor = '#e8e8e8';
button.style.borderColor = '#ccc';
});
button.addEventListener('mouseout', () => {
button.style.backgroundColor = '#f0f0f0';
button.style.borderColor = '#ddd';
});
} else {
// 原有页面的悬停效果
button.addEventListener('mouseover', () => {
button.style.backgroundColor = '#0d4fc3';
button.style.transform = 'translateY(-1px)';
button.style.boxShadow = '0 4px 12px rgba(15, 93, 229, 0.4)';
});
button.addEventListener('mouseout', () => {
button.style.backgroundColor = '#0f5de5';
button.style.transform = 'translateY(0)';
button.style.boxShadow = '0 2px 8px rgba(15, 93, 229, 0.3)';
});
}
return button;
}
// 显示复制成功提示
function showCopySuccess(button) {
const element = document.getElementById(button);
if (!element) return;
if (button === 'batch_bibbtn_li') {
// 批量复制按钮的处理
const batchLink = element.querySelector('a');
if (!batchLink) return;
const originalText = batchLink.textContent;
batchLink.textContent = '✅ 已复制';
batchLink.style.animation = 'successPulse 0.5s ease';
setTimeout(() => {
batchLink.textContent = originalText;
batchLink.style.animation = '';
}, 1500);
} else {
// 普通按钮的处理
const originalText = element.innerHTML;
// 检查是否为检索页面的按钮
const isSearchPageButton = button.startsWith('bibbtn_');
element.innerHTML = `<span style="color: ${isSearchPageButton ? '#0f5de5' : 'white'};">✅ 已复制</span>`;
element.style.animation = 'successPulse 0.5s ease';
setTimeout(() => {
element.innerHTML = originalText;
element.style.animation = '';
}, 1500);
}
}
// 获取引文数据
async function getCitationText(filename = null) {
try {
let params;
if (filename) {
// 高级检索页面的情况
params = {
FileName: filename,
DisplayMode: CITATION_TYPES[currentCitationType],
OrderParam: 0,
OrderType: 'desc',
};
} else {
// 默认情况
params = {
FileName: document.getElementById("paramdbname").getAttribute("value") + '!' +
document.getElementById("paramfilename").getAttribute("value") + '!1!0',
DisplayMode: CITATION_TYPES[currentCitationType],
OrderParam: 0,
OrderType: 'desc',
};
}
// const response = await fetch('https://kns.cnki.net/dm/api/ShowExport', {
const response = await fetch('https://kns.cnki.net/dm8/api/ShowExport', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Referer': 'https://kns.cnki.net/dm/manage/export.html',
},
body: new URLSearchParams(params),
});
const data = await response.text();
// 创建一个临时的div来解析HTML
const tempDiv = document.createElement('div');
tempDiv.innerHTML = data;
let sText = '';
const displayMode = CITATION_TYPES[currentCitationType].toUpperCase();
// 使用类似官方的提取逻辑
if (displayMode === 'MLA' || displayMode === 'APA') {
// 对于MLA和APA格式,直接获取文本内容
const items = tempDiv.querySelectorAll('ul.literature-list li');
sText = Array.from(items)
.map(item => item.textContent
.replace(/\r/g, '')
.replace(/\n/g, '')
.replace(/ /g, '')
.replace(/ /g, ''))
.join('\n');
} else if (displayMode === "NODEFIRST") {
// 对于NODEFIRST格式,直接获取文本内容
const items = tempDiv.querySelectorAll('ul.literature-list li');
sText = Array.from(items)
.map(item => item.innerHTML
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/\r/g, "")
.replace(/\n/g, "")
.replace(/<BR>/g, "\r\n")
.replace(/<br>/g, "\r\n"))
.join('\n');
} else {
// 对于其他格式
const items = tempDiv.querySelectorAll('ul.literature-list>li');
sText = Array.from(items)
.map(item => {
let text = item.innerHTML
.replace(/\r/g, '')
.replace(/\n/g, '')
.replace(/<BR>/g, '\n')
.replace(/<br>/g, '\n')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/ /g, ' ')
.replace(/ {/g, '{')
.replace(/ /g, '');
// 根据不同格式处理空格
if (displayMode === 'GBTREFER') {
text = text.replace(/ /g, '');
} else if (displayMode === 'REFER' || displayMode === 'NEW' || displayMode === 'NEWDEFINE') {
text = text.replace(/ /g, '');
} else if (displayMode === 'SELFDEFINE') {
text = text.replace(/ /g, '');
} else if (displayMode === 'BIBTEX') {
text = text.replace(/author = \{(\s+)/g, 'author = {').replace(/(\s+)and(\s+)/g, ' and ');
}
// 移除所有HTML标签
text = text.replace(/<\/?.+?\/?>/g, '');
return text;
})
.join('\n');
}
if (!sText) {
throw new Error('未找到引文数据');
}
return sText;
} catch (error) {
console.error('获取引文失败:', error);
return null;
}
}
// 复制引文到剪贴板
async function copyText(buttonId = 'bibbtn', filename = null) {
const citationContent = await getCitationText(filename);
if (citationContent) {
GM_setClipboard(citationContent);
showCopySuccess(buttonId);
}
}
// 初始化
function initialize() {
injectStyles();
// 初始化菜单
updateMenuItems();
// 根据页面URL决定按钮添加位置
const currentURL = window.location.href;
if (currentURL.includes('https://kns.cnki.net/kns8s/defaultresult/index') ||
currentURL.includes('https://kns.cnki.net/kns8s/AdvSearch') ||
currentURL.includes('https://kns.cnki.net/kns8s/search')) {
// 高级检索页面 - 添加定时检测
// 添加批量操作按钮
function addBatchButton() {
const batchOpsBox = document.getElementById('batchOpsBox');
if (batchOpsBox && !batchOpsBox.querySelector('li[id="batch_bibbtn_li"]')) {
// 创建新的li元素
const batchLi = document.createElement('li');
batchLi.id = 'batch_bibbtn_li';
batchLi.className = 'export';
// 创建链接
const batchLink = document.createElement('a');
batchLink.href = 'javascript:void(0)';
batchLink.textContent = `批量复制${currentCitationType}`;
batchLink.style.color = '#0f5de5';
// 为链接绑定点击事件
batchLink.addEventListener('click', () => {
const checkedBoxes = document.querySelectorAll('.cbItem:checked');
if (checkedBoxes.length === 0) {
alert('请先选择要复制的文献');
return;
}
const values = Array.from(checkedBoxes).map(cb => cb.value).join(',');
copyText('batch_bibbtn_li', values);
});
// 组装元素
batchLi.appendChild(batchLink);
batchOpsBox.appendChild(batchLi);
}
}
// 定义检测和添加按钮的函数
function checkAndAddButtons() {
// 添加批量操作按钮
addBatchButton();
// 添加单个操作按钮
const operatElements = document.querySelectorAll('.operat, .opts ul.opts-btn');
Array.from(operatElements).forEach((element, index) => {
// 检查该行是否已有按钮
if (element.querySelector('button[id^="bibbtn_"]')) return;
const button = createButton(true); // 传入true表示是高级检索页面
button.id = `bibbtn_${index}`;
// 为opts创建li元素
if (element.classList.contains('opts-btn')) {
const li = document.createElement('li');
li.appendChild(button);
element.insertBefore(li, element.firstChild);
} else {
element.insertBefore(button, element.firstChild);
}
let filename_param = '';
if (element.classList.contains('opts-btn')) {
// 对于opts情况,从父级dd中查找cbItem
const dd = element.closest('dd');
if (dd) {
const cbItem = dd.querySelector('.cbItem');
if (cbItem) {
filename_param = cbItem.value;
}
}
} else {
// 对于operat情况,从tr中查找cbItem
const resultItem = element.closest('tr');
if (resultItem) {
const cbItem = resultItem.querySelector('.cbItem');
if (cbItem) {
filename_param = cbItem.value;
}
}
}
if (filename_param) {
// 为按钮绑定点击事件
$(`#bibbtn_${index}`).click(() => {
copyText(`bibbtn_${index}`, filename_param);
});
}
});
}
// 启动定时检测
setInterval(checkAndAddButtons, 1000);
} else {
// 默认处理
const otherButtons = document.getElementsByClassName('other-btns')[0];
if (otherButtons) {
// 创建按钮元素
const li = document.createElement('li');
li.className = 'btn-bibtex';
li.style.cssText = `
width: 65px;
height: 25px;
`;
const button = createButton();
li.appendChild(button);
// 插入到第一个位置
otherButtons.insertBefore(li, otherButtons.firstChild);
// 绑定点击事件
$("#bibbtn").click(() => copyText());
}
}
}
// 启动脚本
initialize();
})();