npx skills add https://modelscope.cn/skills/@cookjohn/cnki-navigate-pages
cookjohn/cnki-skills
cnki-navigate-pages
Navigate CNKI search result pages (next/previous/specific page) or change sort order. Use when user wants to see more results or change sorting.
Installation
npx skills add cookjohn/cnki-skills --skill cnki-navigate-pages
Similar popular skills
Related neighbors and high-traction skills in the same topics — useful to compare before installing.
Also in this package
Other skills from cookjohn/cnki-skills.
npx skills add cookjohn/cnki-skills
More details
Agent compatibility
Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.
Also listed on
Alternate registries and mirrors of this skill.
Repository health
master
Package contents
Files included with this skill beyond the listing page.
-
skill md
SKILL.md4,785 B -
docs
SUMMARY.md168 B
History
- First seen on skills.sh
- First recorded snapshot · 292 installs
SKILL.md
CNKI Results Pagination and Sorting
All operations use a single async evaluatescript — no snapshot or waitfor needed.
Arguments
$ARGUMENTS should be one of:
next/previous/page N— paginationsort by date/sort by citations/sort by downloads/sort by relevance/sort by comprehensive— sorting
Pagination (single evaluate_script)
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
};
}
Sorting (single evaluate_script)
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
};
}
Output
Navigated to page {page}. Total {total} results.
Results now sorted by {sortBy}.
Tool calls: 1 (evaluate_script only)
Verified selectors
| 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 |
Captcha detection
Check #tcaptchatransformdy element's getBoundingClientRect().top >= 0. Only active when top >= 0 (visible). Pre-loaded SDK sits at top: -1000000px.