cnki-navigate-pages について
CNKI の検索結果ページでページ移動と並べ替えを行うブラウザスキルです。各操作を 1 回の `evaluate_script` で実行し、表示中の CAPTCHA も確認します。
主な機能
- 01前後のページへの移動
- 02指定ページへの移動
- 03日付、被引用数、ダウンロード数、関連度、総合順での並べ替え
- 04表示中の CAPTCHA の検出
活用シーン
- 01CNKI 検索結果の前後ページを閲覧
- 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 を持ちます |
CAPTCHA の検出
#tcaptcha_transform_dy 要素の getBoundingClientRect().top >= 0 を確認します。
top >= 0 の場合のみ有効(表示中)です。事前に読み込まれた SDK は top: -1000000px にあります。
コメント
Markdown 対応