cnki-advanced-search
Perform advanced search on CNKI with field filters like author, title, journal, date range,…
Navigate CNKI search result pages (next/previous/specific page) or change sort order. Use when user wants to see more results or change sorting.
$ npx -y skills add cookjohn/cnki-skills --skill cnki-navigate-pages --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/cnki-navigate-pagesContext preview
The summary Claude sees to decide when to auto-load this skill.
Navigate CNKI search result pages (next/previous/specific page) or change sort order. Use when user wants to see more results or change sorting.
name: cnki-navigate-pages description: Navigate CNKI search result pages (next/previous/specific page) or change sort order. Use when user wants to see more results or change sorting. argument-hint: "[next|previous|page N|sort by date|citations|downloads]"
All operations use a single async `evaluate_script` — no snapshot or wait_for needed.
`$ARGUMENTS` should be one of:
Replace `ACTION_HERE` with `"next"`, `"previous"`, or `"page 3"`:
async () => {
const cap = document.querySelector('#tcaptcha_transform_dy');
if (cap && cap.getBoundingClientRect().top >= 0) return { error: 'captcha' };
const action = "ACTION_HERE";
const pageLinks = document.querySelectorAll('.pages a');
const prevMark = document.querySelector('.countPageMark')?.innerText;
if (action === 'next') {
const next = Array.from(pageLinks).find(a => a.innerText.trim() === '下一页');
if (!next) return { error: 'no_next_page' };
next.click();
} else if (action === 'previous') {
const prev = Array.from(pageLinks).find(a => a.innerText.trim() === '上一页');
if (!prev) return { error: 'no_previous_page' };
prev.click();
} else {
const num = action.replace(/\D/g, '');
const target = Array.from(pageLinks).find(a => a.innerText.trim() === num);
if (!target) return { error: 'page_not_found', available: Array.from(pageLinks).map(a => a.innerText.trim()) };
target.click();
}
// Wait for page change
await new Promise((r, j) => {
let n = 0;
const c = () => {
const mark = document.querySelector('.countPageMark')?.innerText;
if (mark && mark !== prevMark) r();
else if (++n > 30) j('timeout');
else setTimeout(c, 500);
};
setTimeout(c, 1000);
});
const cap2 = document.querySelector('#tcaptcha_transform_dy');
if (cap2 && cap2.getBoundingClientRect().top >= 0) return { error: 'captcha' };
return {
action,
total: document.querySelector('.pagerTitleCell')?.innerText?.match(/([\d,]+)/)?.[1] || '0',
page: document.querySelector('.countPageMark')?.innerText || '?',
url: location.href
};
}Replace `SORT_HERE` with `"relevance"`, `"date"`, `"citations"`, `"downloads"`, or `"comprehensive"`:
async () => {
const cap = document.querySelector('#tcaptcha_transform_dy');
if (cap && cap.getBoundingClientRect().top >= 0) return { error: 'captcha' };
const sortBy = "SORT_HERE";
const idMap = {
'relevance': 'FFD', 'date': 'PT',
'citations': 'CF', 'downloads': 'DFR', 'comprehensive': 'ZH'
};
const liId = idMap[sortBy];
if (!liId) return { error: 'invalid_sort', valid: Object.keys(idMap) };
const li = document.querySelector('#orderList li#' + liId);
if (!li) return { error: 'sort_option_not_found' };
const prevMark = document.querySelector('.countPageMark')?.innerText;
li.click();
// Wait for results to refresh (page resets to 1)
await new Promise((r, j) => {
let n = 0;
const c = () => {
const mark = document.querySelector('.countPageMark')?.innerText;
if (mark && mark !== prevMark) r();
else if (++n > 30) j('timeout');
else setTimeout(c, 500);
};
setTimeout(c, 1000);
});
return {
sortBy,
total: document.querySelector('.pagerTitleCell')?.innerText?.match(/([\d,]+)/)?.[1] || '0',
page: document.querySelector('.countPageMark')?.innerText || '?',
activeLi: document.querySelector('#orderList li.cur')?.innerText?.trim(),
url: location.href
};
}> Navigated to page {page}. Total {total} results. > Results now sorted by {sortBy}.
| Element | Selector | Notes | |---------|----------|-------| | Page links | `.pages a` | numbers + 上一页/下一页 | | Current page | `.pages a.cur` | | | Next page | text `下一页`, class `pagesnums` | | | Page counter | `.countPageMark` | text "1/300" | | Sort container | `#sortList` (`.order-group`) | | | Sort options | `#orderList li` | click to sort | | 相关度 | `li#FFD` | data-sort="FFD" | | 发表时间 | `li#PT` | data-sort="PT" | | 被引 | `li#CF` | data-sort="CF" | | 下载 | `li#DFR` | data-sort="DFR" | | 综合 | `li#ZH` | data-sort="ZH" | | Active sort | `#orderList li.cur` | has class `cur` |
Check `#tcaptcha_transform_dy` element's `getBoundingClientRect().top >= 0`. Only active when `top >= 0` (visible). Pre-loaded SDK sits at `top: -1000000px`.
CNKI (中国知网) skills for Claude Code — search, browse journals, download PDFs, export to Zotero via Chrome DevTools MCP
Repo: cookjohn/cnki-skills
Perform advanced search on CNKI with field filters like author, title, journal, date range,…
Download a paper PDF/CAJ from CNKI. Requires user to be logged in. Use when user wants to…
Export paper from CNKI and push to Zotero, or save as RIS file. Use when user wants to save a…
Query journal indexing/inclusion status on CNKI - check which databases include a journal…
Search for journals/publications on CNKI by name, ISSN, CN, or sponsor. Use when the user…
Browse journal issues, view table of contents, and download original TOC PDF from CNKI. Use…