mcpField
C
cnki-paper-detail

cnki-paper-detail

github.com/cookjohn生产力1.0k659 次安装33 周前更新
代码仓库

关于 cnki-paper-detail

从 CNKI 论文详情页提取完整元数据的技能,适用于整理和查看论文信息。支持页面脚本提取,并可在失败时依据无障碍页面结构解析。

主要功能

  1. 01提取标题与作者
  2. 02获取作者单位和摘要
  3. 03读取关键词、基金与分类号
  4. 04识别网络首发状态
  5. 05支持页面结构解析回退

适用场景

  1. 01整理 CNKI 论文的书目信息
  2. 02从详情页收集摘要和关键词
  3. 03验证码通过后继续读取论文信息

MCP 相关

使用 Chrome DevTools MCP 导航论文页面、检测验证码,并执行页面脚本或读取页面快照。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/cookjohn/cnki-skills --skill cnki-paper-detail

安装后在 Claude Code 中输入/cnki-paper-detail确认已加载。

详细介绍

CNKI 论文详情提取

从 CNKI 论文详情页提取完整元数据。

参数

$ARGUMENTS 是可选的 CNKI 论文详情页 URL(包含 kcms2/article/abstract)。如果未提供,则假定当前页面已经是论文详情页。

步骤

1. 导航至论文页面(如果提供了 URL)

如果 $ARGUMENTS 包含 URL:

  • 使用 mcp__chrome-devtools__navigate_page 并传入该 URL。
  • 使用 mcp__chrome-devtools__wait_for,文本设为 ["摘要"],超时时间设为 15000。
2. 检查验证码

使用 mcp__chrome-devtools__take_snapshot。如果发现“拖动下方拼图完成验证”,请通知用户:

CNKI 正在显示滑块验证码。请在 Chrome 浏览器中手动完成拼图验证,完成后告诉我继续。

3. 通过 JavaScript 提取论文元数据

使用 mcp__chrome-devtools__evaluate_script 并传入此函数:

() => {
  const brief = document.querySelector('.brief');
  if (!brief) return { error: 'Paper detail section (.brief) not found' };

  // Title
  const title = brief.querySelector('h1')?.innerText?.trim()
    ?.replace(/\s*附视频\s*$/, '')  // remove "附视频" suffix
    ?.replace(/\s*网络首发\s*$/, ''); // remove "网络首发" suffix

  // Authors - first h3.author contains author links with sup tags
  const authorH3s = brief.querySelectorAll('h3.author');
  const authorSection = authorH3s[0];
  const authors = [];
  if (authorSection) {
    const authorLinks = authorSection.querySelectorAll('a');
    authorLinks.forEach(a => {
      const name = a.innerText?.replace(/\d+$/, '').trim();
      const supMatch = a.innerText?.match(/(\d+)$/);
      const affiliationNum = supMatch ? supMatch[1] : '';
      authors.push({ name, affiliationNum });
    });
  }

  // Affiliations - second h3.author contains org links
  const affiliations = [];
  if (authorH3s.length > 1) {
    const orgLinks = authorH3s[1].querySelectorAll('a');
    orgLinks.forEach(a => {
      affiliations.push(a.innerText?.trim());
    });
  }

  // Abstract
  const abstractEl = document.querySelector('.abstract-text');
  const abstract = abstractEl?.innerText?.trim() || '';

  // Keywords
  const keywordsP = document.querySelector('p.keywords');
  const keywords = keywordsP
    ? Array.from(keywordsP.querySelectorAll('a')).map(a => a.innerText?.replace(/;$/, '').trim())
    : [];

  // Fund
  const fundsP = document.querySelector('p.funds');
  const fund = fundsP?.innerText?.trim() || '';

  // Classification code
  const clcCode = document.querySelector('.clc-code');
  const classification = clcCode?.innerText?.trim() || '';

  // Journal/source
  const docTop = document.querySelector('.doc-top');
  const journal = docTop?.querySelector('a')?.innerText?.trim() || '';

  // Online first / publication info
  const headTime = document.querySelector('.head-time');
  const pubInfo = headTime?.innerText?.trim() || '';

  // Is online first?
  const isOnlineFirst = !!brief.querySelector('.icon-shoufa');

  // Article outline/TOC
  const catalogList = document.querySelector('.catalog-list, .catalog-listDiv');
  const toc = catalogList?.innerText?.trim() || '';

  // Citation network counts
  const citationTabs = document.querySelectorAll('ul.module-tab.tpl_lieteratures li');
  const citationInfo = {};
  citationTabs.forEach(li => {
    const id = li.getAttribute('data-id');
    const text = li.innerText?.trim();
    const countMatch = text.match(/(\d+)/);
    if (id) {
      citationInfo[id] = {
        label: text.replace(/\d+/, '').trim(),
        count: countMatch ? parseInt(countMatch[1]) : 0
      };
    }
  });

  return {
    title,
    authors,
    affiliations,
    abstract,
    keywords,
    fund,
    classification,
    journal,
    pubInfo,
    isOnlineFirst,
    toc,
    citationInfo
  };
}
4. 格式化并展示输出
## {title} {isOnlineFirst ? "[网络首发]" : ""}

**Authors:**
{For each author: "- {name} ({affiliation})"}

**Affiliations:**
{For each affiliation: "- {affiliation}"}

**Journal:** {journal}
**Publication Info:** {pubInfo}

**Abstract:**
{abstract}

**Keywords:** {keywords joined by ", "}

**Fund:** {fund}
**Classification:** {classification}

**Citation Network:**
{For each citation type: "- {label}: {count}"}
5. 回退方案:基于快照解析

如果 JS 提取失败,则使用 mcp__chrome-devtools__take_snapshot 并解析无障碍树:

  • 标题:heading 的 1 级元素
  • 作者:URL 包含 kcms2/author/detail 的 link 元素
  • 机构:URL 包含 kcms2/organ/detail 的 link 元素
  • 摘要:"摘要:"后面的 StaticText
  • 关键词:URL 包含 kcms2/keyword/detail 的 link 元素
  • 基金:"基金资助:"后面的 link 元素
  • 分类号:"分类号:"后面的 StaticText

已验证的 DOM 选择器

数据选择器说明
论文区域.brief论文主要信息容器
标题.brief h1可能包含图标,需要提取纯文本
作者.brief h3.author:first-of-type a文本带有上标数字(例如,“张三1”)
机构.brief h3.author:nth-of-type(2) a文本以“N.”开头(例如,“1.北京大学”)
摘要.abstract-text完整摘要文本
关键词p.keywords a以分号分隔的关键词链接
基金p.funds基金信息文本
分类号.clc-code中图分类号代码
期刊.doc-top a来源期刊链接
网络首发.brief .icon-shoufa论文为网络首发时显示
引文选项卡ul.module-tab.tpl_lieteratures lidata-id 属性用于标识类型

评论

支持 Markdown