cnki-navigate-pages

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

CNKI Results Pagination and Sorting

CNKI搜索结果分页与排序

All operations use a single async
evaluate_script
— no snapshot or wait_for needed.
所有操作仅需调用一次异步
evaluate_script
即可完成,无需截图或等待操作。

Arguments

参数

$ARGUMENTS
should be one of:
  • next
    /
    previous
    /
    page N
    — pagination
  • sort by date
    /
    sort by citations
    /
    sort by downloads
    /
    sort by relevance
    /
    sort by comprehensive
    — sorting
$ARGUMENTS
应为以下选项之一:
  • next
    /
    previous
    /
    page N
    — 分页操作
  • sort by date
    /
    sort by citations
    /
    sort by downloads
    /
    sort by relevance
    /
    sort by comprehensive
    — 排序操作

Pagination (single evaluate_script)

分页(仅需一次evaluate_script调用)

Replace
ACTION_HERE
with
"next"
,
"previous"
, or
"page 3"
:
javascript
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
  };
}
ACTION_HERE
替换为
"next"
"previous"
"page 3"
这类值:
javascript
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)

排序(仅需一次evaluate_script调用)

Replace
SORT_HERE
with
"relevance"
,
"date"
,
"citations"
,
"downloads"
, or
"comprehensive"
:
javascript
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
  };
}
SORT_HERE
替换为
"relevance"
"date"
"citations"
"downloads"
"comprehensive"
javascript
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}.
已跳转至第{page}页,共{total}条结果。 结果当前按{sortBy}排序。

Tool calls: 1 (evaluate_script only)

工具调用:1次(仅调用evaluate_script)

Verified selectors

已验证选择器

ElementSelectorNotes
Page links
.pages a
numbers + 上一页/下一页
Current page
.pages a.cur
Next pagetext
下一页
, 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
元素选择器备注
页码链接
.pages a
数字 + 上一页/下一页
当前页码
.pages a.cur
下一页文本
下一页
,class
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 detection

验证码检测

Check
#tcaptcha_transform_dy
element's
getBoundingClientRect().top >= 0
. Only active when
top >= 0
(visible). Pre-loaded SDK sits at
top: -1000000px
.
检查
#tcaptcha_transform_dy
元素的
getBoundingClientRect().top >= 0
是否成立。仅当
top >= 0
时验证码可见,预加载的SDK默认位置为
top: -1000000px