mcpField
C
cnki-navigate-pages

cnki-navigate-pages

github.com/cookjohn生産性1.0k332 回インストール33 週間前に更新
リポジトリ

cnki-navigate-pages について

CNKI の検索結果ページでページ移動と並べ替えを行うブラウザスキルです。各操作を 1 回の `evaluate_script` で実行し、表示中の CAPTCHA も確認します。

主な機能

  1. 01前後のページへの移動
  2. 02指定ページへの移動
  3. 03日付、被引用数、ダウンロード数、関連度、総合順での並べ替え
  4. 04表示中の CAPTCHA の検出

活用シーン

  1. 01CNKI 検索結果の前後ページを閲覧
  2. 02指定した結果ページへ直接移動
  3. 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#FFDdata-sort="FFD"
発表時期li#PTdata-sort="PT"
被引用数li#CFdata-sort="CF"
ダウンロード数li#DFRdata-sort="DFR"
総合li#ZHdata-sort="ZH"
選択中の並べ替え#orderList li.curクラス cur を持ちます

CAPTCHA の検出

#tcaptcha_transform_dy 要素の getBoundingClientRect().top >= 0 を確認します。 top >= 0 の場合のみ有効(表示中)です。事前に読み込まれた SDK は top: -1000000px にあります。

コメント