cnki-export
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseCNKI Export & Zotero Integration
CNKI 导出与 Zotero 集成
Export paper citation data from CNKI and push directly to Zotero, or save as RIS file.
从CNKI导出论文引用数据,直接推送至Zotero,或保存为RIS文件。
Arguments
参数说明
- (default) — push to Zotero desktop via local API
zotero - — save as .ris file
ris - — output GB/T 7714 citation text
gb - Optionally include a paper URL
- (默认)——通过本地API推送至Zotero桌面端
zotero - ——保存为.ris文件
ris - ——输出GB/T 7714格式引用文本
gb - 可选传入论文URL
Mode Selection
模式选择
Choose the right mode based on context:
| Context | Mode | Tool calls |
|---|---|---|
| On a paper detail page | Single export (Step 1A) | 1 evaluate + 1 bash = 2 |
| On a search results page, save all/selected | Batch export (Step 1B) | 1 evaluate + 1 bash = 2 |
| Need to search then save | Use cnki-search first, then batch export | 4 total |
Always prefer batch export (1B) when multiple papers need saving. It avoids navigating to each detail page (saves ~3 calls per paper).
根据使用场景选择合适的模式:
| 场景 | 模式 | 工具调用次数 |
|---|---|---|
| 在论文详情页 | 单篇导出(步骤1A) | 1次evaluate + 1次bash = 2次 |
| 在搜索结果页,保存全部/选中论文 | 批量导出(步骤1B) | 1次evaluate + 1次bash = 2次 |
| 需要先搜索再保存 | 先使用cnki-search,再进行批量导出 | 共4次 |
当需要保存多篇论文时,优先选择批量导出(1B)。无需跳转至每篇论文的详情页(每篇论文可减少约3次调用)。
Steps
操作步骤
1A. Single export: from paper detail page
1A. 单篇导出:从论文详情页
Use :
mcp__chrome-devtools__evaluate_scriptjavascript
async () => {
const url = document.querySelector('#export-url')?.value;
const params = document.querySelector('#export-id')?.value;
const uniplatform = new URLSearchParams(window.location.search).get('uniplatform') || 'NZKPT';
if (!url || !params) return { error: 'Not on a paper detail page' };
const resp = await fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({ filename: params, displaymode: 'GBTREFER,elearning,EndNote', uniplatform })
});
const data = await resp.json();
if (data.code !== 1) return { error: data.msg };
const result = {};
for (const item of data.data) {
result[item.mode] = item.value[0];
}
const body = document.body.innerText;
result.pageUrl = window.location.href;
result.issn = body.match(/ISSN[::]\s*(\S+)/)?.[1] || '';
result.dbcode = document.querySelector('#paramdbcode')?.value || '';
result.dbname = document.querySelector('#paramdbname')?.value || '';
result.filename = document.querySelector('#paramfilename')?.value || '';
return result;
}调用:
mcp__chrome-devtools__evaluate_scriptjavascript
async () => {
const url = document.querySelector('#export-url')?.value;
const params = document.querySelector('#export-id')?.value;
const uniplatform = new URLSearchParams(window.location.search).get('uniplatform') || 'NZKPT';
if (!url || !params) return { error: 'Not on a paper detail page' };
const resp = await fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({ filename: params, displaymode: 'GBTREFER,elearning,EndNote', uniplatform })
});
const data = await resp.json();
if (data.code !== 1) return { error: data.msg };
const result = {};
for (const item of data.data) {
result[item.mode] = item.value[0];
}
const body = document.body.innerText;
result.pageUrl = window.location.href;
result.issn = body.match(/ISSN[::]\s*(\S+)/)?.[1] || '';
result.dbcode = document.querySelector('#paramdbcode')?.value || '';
result.dbname = document.querySelector('#paramdbname')?.value || '';
result.filename = document.querySelector('#paramfilename')?.value || '';
return result;
}1B. Batch export: from search results page (PREFERRED for multiple papers)
1B. 批量导出:从搜索结果页(多篇论文优先选择)
On any CNKI search results page, extract checkbox values and call the export API directly — no need to navigate to detail pages.
Key discovery: checkbox === detail page (same encrypted ID).
input.cbItemvalue#export-idUse :
mcp__chrome-devtools__evaluate_scriptjavascript
async () => {
const API_URL = 'https://kns.cnki.net/dm8/API/GetExport';
// Get all checkbox values (= export encrypted IDs)
const checkboxes = document.querySelectorAll('.result-table-list tbody input.cbItem');
const rows = document.querySelectorAll('.result-table-list tbody tr');
if (checkboxes.length === 0) return { error: 'No results on page' };
const allPapers = [];
for (let i = 0; i < checkboxes.length; i++) {
const exportId = checkboxes[i].value;
const paperUrl = rows[i]?.querySelector('td.name a.fz14')?.href || '';
const resp = await fetch(API_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({ filename: exportId, displaymode: 'GBTREFER,elearning,EndNote', uniplatform: 'NZKPT' })
});
const data = await resp.json();
if (data.code === 1) {
const result = {};
for (const item of data.data) { result[item.mode] = item.value[0]; }
result.pageUrl = paperUrl;
// Extract ISSN from ENDNOTE %@ field
const issnMatch = result.ENDNOTE?.match(/%@\s*([^\s<]+)/);
result.issn = issnMatch ? issnMatch[1] : '';
result.dbcode = 'CJFQ';
result.dbname = '';
result.filename = '';
allPapers.push(result);
}
}
return allPapers; // JSON array, directly writable to file for Python script
}To export only specific papers (e.g. #1, #3, #5), filter by index:
javascript
// Replace the for loop condition:
const indices = [0, 2, 4]; // 0-indexed: papers #1, #3, #5
for (let i = 0; i < checkboxes.length; i++) {
if (!indices.includes(i)) continue;
// ... rest same
}在任意CNKI搜索结果页,提取复选框值并直接调用导出API —— 无需跳转至详情页。
关键发现:复选框的值 === 详情页的(相同的加密ID)。
input.cbItemvalue#export-id调用:
mcp__chrome-devtools__evaluate_scriptjavascript
async () => {
const API_URL = 'https://kns.cnki.net/dm8/API/GetExport';
// 获取所有复选框的值(=导出加密ID)
const checkboxes = document.querySelectorAll('.result-table-list tbody input.cbItem');
const rows = document.querySelectorAll('.result-table-list tbody tr');
if (checkboxes.length === 0) return { error: 'No results on page' };
const allPapers = [];
for (let i = 0; i < checkboxes.length; i++) {
const exportId = checkboxes[i].value;
const paperUrl = rows[i]?.querySelector('td.name a.fz14')?.href || '';
const resp = await fetch(API_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({ filename: exportId, displaymode: 'GBTREFER,elearning,EndNote', uniplatform: 'NZKPT' })
});
const data = await resp.json();
if (data.code === 1) {
const result = {};
for (const item of data.data) { result[item.mode] = item.value[0]; }
result.pageUrl = paperUrl;
// 从ENDNOTE的%@字段提取ISSN
const issnMatch = result.ENDNOTE?.match(/%@\s*([^\s<]+)/);
result.issn = issnMatch ? issnMatch[1] : '';
result.dbcode = 'CJFQ';
result.dbname = '';
result.filename = '';
allPapers.push(result);
}
}
return allPapers; // JSON数组,可直接写入文件供Python脚本使用
}仅导出特定论文(例如第1、3、5篇),可通过索引过滤:
javascript
// 替换for循环的条件:
const indices = [0, 2, 4]; // 索引从0开始:对应第1、3、5篇论文
for (let i = 0; i < checkboxes.length; i++) {
if (!indices.includes(i)) continue;
// ... 其余代码不变
}2. Push to Zotero
2. 推送至Zotero
Save the export data (single object or JSON array) to a temp file, then run the Python script:
bash
python "e:/cnki/.claude/skills/cnki-export/scripts/push_to_zotero.py" /tmp/papers.jsonThe Python script handles both single paper and batch JSON input.
{}[{}, {}, ...]- UTF-8 encoding (avoids Windows encoding issues)
- Parsing ELEARNING format into Zotero item fields
- Calling
POST http://127.0.0.1:23119/connector/saveItems - Returns: 201 = success, 500 = error, 0 = Zotero not running
将导出数据(单个对象或JSON数组)保存到临时文件,然后运行Python脚本:
bash
python "e:/cnki/.claude/skills/cnki-export/scripts/push_to_zotero.py" /tmp/papers.json该Python脚本支持单篇论文和批量论文两种JSON输入格式。
{}[{}, {}, ...]- UTF-8编码(避免Windows编码问题)
- 将ELEARNING格式解析为Zotero条目字段
- 调用
POST http://127.0.0.1:23119/connector/saveItems - 返回值:201 = 成功,500 = 错误,0 = Zotero未运行
3. Report result
3. 结果反馈
Single:
已将论文添加到 Zotero:
标题: {title}
作者: {authors}
期刊: {journal}
GB/T 7714 引用: {gbt_citation}Batch:
已批量添加 {count} 篇论文到 Zotero:
1. {title1} ({journal1})
2. {title2} ({journal2})
...单篇导出反馈:
已将论文添加到 Zotero:
标题: {title}
作者: {authors}
期刊: {journal}
GB/T 7714 引用: {gbt_citation}批量导出反馈:
已批量添加 {count} 篇论文到 Zotero:
1. {title1} ({journal1})
2. {title2} ({journal2})
...Export API Reference
导出API参考
| Parameter | Value | Source |
|---|---|---|
| API URL | | Fixed, works from any page |
| filename | Encrypted ID | Detail page: |
| displaymode | | Comma-separated modes |
| uniplatform | | Required |
| 参数 | 值 | 来源 |
|---|---|---|
| API URL | | 固定值,支持任意页面调用 |
| filename | 加密ID | 详情页: |
| displaymode | | 逗号分隔的模式列表 |
| uniplatform | | 必填参数 |
Verified selectors
已验证的选择器
| Element | Selector | Page |
|---|---|---|
| Export URL | | Detail page only |
| Export ID | | Detail page only |
| Checkbox (= export ID) | | Search results page |
| Result rows | | Search results page |
| Title link | | Search results page |
| 元素 | 选择器 | 页面 |
|---|---|---|
| 导出URL | | 仅详情页 |
| 导出ID | | 仅详情页 |
| 复选框(=导出ID) | | 搜索结果页 |
| 结果行 | | 搜索结果页 |
| 标题链接 | | 搜索结果页 |
Zotero API Reference
Zotero API参考
POST http://127.0.0.1:23119/connector/saveItems
Content-Type: application/json
X-Zotero-Connector-API-Version: 3Response: 201 = created, 500 = error
Collection: Saves to Zotero's currently selected collection.
Query collections:
bash
python "e:/cnki/.claude/skills/cnki-export/scripts/push_to_zotero.py" --listPOST http://127.0.0.1:23119/connector/saveItems
Content-Type: application/json
X-Zotero-Connector-API-Version: 3响应码: 201 = 创建成功,500 = 错误
保存位置: 保存至Zotero当前选中的集合中。
查询集合列表:
bash
python "e:/cnki/.claude/skills/cnki-export/scripts/push_to_zotero.py" --listImportant Notes
重要注意事项
- Windows encoding: Must use Python script, cannot pass Chinese JSON via bash/curl directly
- Zotero must be running: requires Zotero desktop in background
localhost:23119 - Chinese authors: Use field (single field, not split),
namecreatorType: "author" - Batch export saves ~90% tool calls: 9 papers: 33 calls → 3 calls
- CNKI Export API: must be encrypted ID (
filenameor#export-idvalue), NOTinput.cbItem#paramfilename
- Windows编码问题: 必须使用Python脚本,无法直接通过bash/curl传递中文JSON
- Zotero需处于运行状态: 要求Zotero桌面端在后台运行
localhost:23119 - 中文作者: 使用字段(单个字段,不拆分),
namecreatorType: "author" - 批量导出可节省约90%的工具调用: 9篇论文:33次调用 → 3次调用
- CNKI导出API: 必须为加密ID(
filename或#export-id的value值),而非input.cbItem#paramfilename