关于 cnki-navigate-pages
用于操作 CNKI 结果页分页和排序的浏览器技能。两类操作均通过一次 `evaluate_script` 完成,并检查可见的验证码。
主要功能
- 01前往上一页或下一页
- 02跳转到指定页码
- 03按日期、被引、下载、相关度或综合排序
- 04检测可见的验证码
适用场景
- 01浏览 CNKI 搜索结果的前后页面
- 02直接跳转到已知结果页
- 03按发表时间或被引次数重新排列结果
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ cookjohn/ cnki-skills --skill cnki-navigate-pages安装后在 Claude Code 中输入/cnki-navigate-pages确认已加载。
详细介绍
CNKI 结果分页与排序
所有操作均使用单个异步 evaluate_script,无需快照或 wait_for。
参数
$ARGUMENTS 应为以下之一:
next/previous/page N— 分页sort by date/sort by citations/sort by downloads/sort by relevance/sort by comprehensive— 排序
分页(单个 evaluate_script)
将 ACTION_HERE 替换为 "next"、"previous" 或 "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
};
}
排序(单个 evaluate_script)
将 SORT_HERE 替换为 "relevance"、"date"、"citations"、"downloads" 或 "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
};
}
输出
已跳转至第 {page} 页。共 {total} 条结果。 结果现已按 {sortBy} 排序。
工具调用:1 次(仅 evaluate_script)
已验证的选择器
| 元素 | 选择器 | 备注 |
|---|---|---|
| 页面链接 | .pages a | 数字 + 上一页/下一页 |
| 当前页 | .pages a.cur | |
| 下一页 | 文本 下一页,类名 pagesnums | |
| 页数计数器 | .countPageMark | 文本 "1/300" |
| 排序容器 | #sortList (.order-group) | |
| 排序选项 | #orderList li | 点击以排序 |
| 相关度 | 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" |
| 当前排序 | #orderList li.cur | 带有类名 cur |
验证码检测
检查 #tcaptcha_transform_dy 元素的 getBoundingClientRect().top >= 0。
仅当 top >= 0(可见)时才处于激活状态。预加载的 SDK 位于 top: -1000000px。
评论
支持 Markdown