편집자 노트

666489/dsh-nature-papers

A DSH Web plugin that scrapes nature.com in real time for the latest papers on biochemistry / bioinformatics, ranks them with journal impact factor (IF) as the primary quality criterion, and shows 3 papers per day in a floating panel at the bottom-right corner of the page — with direct links to the originals, journal…

이것은 DeepSeek Harness(DSH) 플러그인입니다. 이 사이트는 GitHub README, 설치 정보, 유지보수 상태, 공개 보안 시그널을 모아 보여줍니다.

dsh-nature-papers

DSH Web 插件:实时爬取 nature.com 上有关生物化学 / 生物信息学的最新论文,以期刊影响因子(IF)为第一优先排序,每天在页面右下角展示 3 篇优质论文并提供原文直达链接、期刊 IF、内容简介;所有历史推荐按日期(年月日)存档,可随时回查;面板底部提供一键「退出 Harness」。

本文档为完整技术实现说明(开源文档),包含架构、每个功能的实现细节、Nature 反爬自动退化机制、数据格式与接口规范。


目录

  1. 功能一览
  2. 目录结构
  3. 架构总览:DSH 插件模型
  4. 功能实现细节
    • 4.1 实时爬取(nature.com 搜索页)
    • 4.2 Nature 反爬自动退化(Client Challenge → PubMed)
    • 4.3 影响因子优先排序
    • 4.4 内容简介(摘要抓取链)
    • 4.5 每日 3 篇与缓存
    • 4.6 历史记录与去重
    • 4.7 实时刷新
    • 4.8 右下角面板(客户端)
    • 4.9 退出 Harness
  5. HTTP 接口规范
  6. 配置项
  7. 存储格式
  8. 限速、容错与反爬规避
  9. 已知限制与局限
  10. 运维:安装 / 更新 / 启停 / 卸载

功能一览

  • 🧬 每日 3 篇:每天自动更新(跨天自动重新爬取),同一天内缓存固定,不反复变化。
  • 🏆 影响因子优先:内置 ~90 种期刊的近似 JCR 影响因子表,候选按「IF 降序 → 发表时间新序」排序,卡片标注 IF x.x
  • 🔗 链接直达:标题直达 nature.com 原文(新标签页),附 DOI。
  • 📄 内容简介:优先抓取文章页 Abstract,失败退回搜索页摘要;支持展开/收起。
  • 📜 历史记录:按 YYYY-MM-DD 分组存档,可展开回查任意一天。
  • 🔄 实时刷新:按钮触发立即重爬并换选(优先未推荐过的论文)。
  • 退出 Harness:二次确认后优雅关闭 DSH 服务器进程。
  • 🛡 反爬自动退化:nature.com 下发 Client Challenge 时,自动切换 PubMed E-utilities 镜像(仍限定 Nature Portfolio 期刊,链接仍指向 nature.com)。

目录结构

nature-papers/
├── package.json      # 包声明:dsh.client 元数据、exports 映射
├── README.md         # 英文文档
├── README_zh.md      # 中文文档(本文档)
├── LICENSE           # MIT 许可证
├── .gitignore
├── install.ps1       # 安装/更新/卸载脚本
├── start-dsh.ps1     # 启动 dsh web 脚本
├── stop-dsh.ps1      # 关闭 dsh web 脚本
├── restart-dsh.ps1   # 重启 dsh web 脚本
├── test-scraper.mjs  # 爬虫核心独立测试
└── lib/
    ├── index.js      # 宿主端(Cordis 插件):路由 / 存储 / 每日调度 / 退出
    ├── scraper.js    # 爬取核心(纯 Node,可独立测试):双数据源、解析、排序
    ├── if-data.js    # 期刊影响因子参考表 + 名称归一化
    └── client.js     # 浏览器端 bundle:右下角面板(shell.overlay 槽位)

配套脚本位于仓库根目录(下文命令均在仓库根目录下执行):

脚本用途
install.ps1同步代码到安装目录 + 写入 cordis.patch.yml 条目(支持 -Uninstall)
start-dsh.ps1后台启动 dsh web(隐藏窗口,日志落盘)
stop-dsh.ps1按端口精确关闭 dsh web 进程
restart-dsh.ps1杀旧进程 → 确认端口释放 → 启动新进程 → 自检插件接口
test-scraper.mjs爬虫核心独立测试(不依赖 Cordis)

架构总览:DSH 插件模型

DSH Web 是一个 Cordis 插件树:web profile 的空根配置 cordis.yml 由多层 patch 组合(@deepseek-ai/dsh-base@deepseek-ai/dsh-web-app 两个 bundle 层 + 用户层 cordis.patch.yml)。挂载插件 = 在组合树中插入一个 loader 条目,并让它被加载激活。

挂载链路(宿主端)

  1. 放置包:把本目录复制到 $DSH_HOME\profiles\node_modules\dsh-nature-papers(真实目录)。DSH 服务器按 Node 裸模块解析规则从 profile 目录向上查找,因此 import('dsh-nature-papers') 与依赖 @deepseek-ai/schemastery 都能解析。

  2. 注册条目cordis.patch.yml 写入(install.ps1 自动维护):

    - insert:
        - id: nature-papers
          name: dsh-nature-papers
          config:
            query: 'bioinformatics biochemistry'
            count: 3
            requestDelayMs: 1000
            storageFile: !!js dshHomePath('storages/nature-papers.json')
    

    insert patch 把条目追加进组合树;!!js 表达式在条目激活时求值(eval 作用域由 boot() 注入 dshHomePath)。

  3. 激活:loader 按名字 import() 模块 → unwrapExports 取默认导出 { name, inject, Config, apply } → Cordis 解析 inject: ['webServer'](等待服务就绪)→ 用 schemastery Config 校验 config → 执行 apply(ctx, config):注册 5 条 HTTP 路由、装载/落盘历史存储、启动每日轮换定时器。条目被 stop/update 时,ctx.effect 的 disposer 会注销路由并清理定时器。

挂载链路(客户端)

lib/client.js 是浏览器端 bundle,通过包声明 dsh.client(platform: web)与 exports["./client"] 被识别:

  1. dsh-client-modules(宿主端)扫描 loader 树中声明 dsh.client 的包 → 把 bundle 内容哈希进 window.__DSH_BOOT__ 清单 → 挂到 /plugins/dsh-nature-papers/client.js
  2. 页面加载时 shell 读取 __DSH_BOOT__ → 加载 bundle 脚本 → bundle 调用 window.__ModuleLoader__.load({ id, factory }) 注册工厂(惰性 CJS:注册 ≠ 执行)。
  3. Cordis 客户端 loader 物化工厂(factory(require)require('react') 可用)→ 得到插件对象 { name, inject: ['slots'], apply }
  4. apply() 通过 ctx.slots.inject('shell.overlay', ...) 把面板组件注册进 shell.overlay 槽位——该槽位由 ui-layout 的 AppFrame 覆盖层(position:absolute; inset:0)渲染,面板用 position:absolute; right:16px; bottom:16px 定位,即页面右下角

数据流

浏览器面板 ──fetch──▶ /plugins/dsh-nature-papers/* ──▶ 宿主端路由
                                                        │
                                          ┌─────────────┴──────────────┐
                                    数据源 A: nature.com 搜索页      数据源 B: PubMed E-utilities
                                          └─────────────┬──────────────┘
                                                        ▼
                                             IF 排序 → 去重 → 摘要 enrich
                                                        ▼
                                         $DSH_HOME/storages/nature-papers.json

功能实现细节

4.1 实时爬取(nature.com 搜索页)

请求构造scrapeNatureSearch):

  • URL:https://www.nature.com/search?q=<query>&order=date_descquery 为空格分隔的关键词(AND 语义),默认 bioinformatics biochemistry
  • 分页:最多翻 3 页(&page=2/3);当一页行数 < 10 或候选数达标(maxCandidates,默认 90)时提前停止;页间延迟 requestDelayMs
  • 请求头:浏览器 UA + accept: text/html,...;超时 requestTimeoutMs;失败重试 1 次(间隔 1.2s)。

行解析:按 <li class="app-article-list-row__item"> 切分每条结果,正则提取字段:

字段定位标记说明
标题<h3 class="c-card__title">…<a href="/articles/<id>">去标签、解实体
链接href="(/articles/[a-zA-Z0-9-]+)"拼为 https://www.nature.com/articles/<id>
类型data-test="article.type">…<span class="c-meta__type">命中黑名单(news/comment/editorial/news & views/…)则丢弃
期刊data-test="journal-title-and-link">纯文本
日期<time … datetime="YYYY-MM-DD">ISO 日期,用于次级排序
摘要data-test="article-description">…<p>…</p>搜索页自带 1~2 句简介(简介兜底)
开放获取行内含 u-color-open-access布尔标记
DOI由文章 id 推导:/^s\d+-\d+/10.1038/<id>非该格式(如 BMC 期刊)为 null

4.2 Nature 反爬自动退化(Client Challenge → PubMed)

背景:nature.com 对无 JS 的爬虫会下发一个 JS 挑战页("Client Challenge",约 3KB 的 HTML,内含一段加载脚本的 loadScript 代码),纯 HTTP 客户端无法通过(需要真实浏览器执行 JS 换取 cookie)。

检测(两处):

  • 搜索页:html.includes('Client Challenge') || !html.includes('app-article-list-row') → 抛 nature.com 触发了反爬校验(Client Challenge),已切换备用源
  • 文章页:命中 Client Challenge 时该篇摘要视为不可得,返回 null,走简介兜底。

退化流程generateEntry):

  1. 先试数据源 A(nature.com 实时爬取);

  2. 抛错后自动转数据源 B(PubMed E-utilities),不中断用户请求;

  3. 数据源 B 的查询构造:

    • esearchterm = ("Nature"[ta] OR "Nature Communications"[ta] OR …) AND (bioinformatics[tiab] OR biochemistry[tiab] OR "computational biology"[tiab] OR …)sort=date&retmax=90 —— 用 [ta] 期刊字段把检索范围钉死在 ~55 个 Nature Portfolio 期刊上,用 [tiab] 主题词保证话题相关性;
    • esummary:一次取全部命中(最多 90 条)的标题、期刊全名、发布日期、DOI;
    • 新闻过滤:Nature 新闻稿的 DOI 形如 10.1038/d41586-…doi.startsWith('10.1038/d4') 直接丢弃,只保留研究类论文;
    • 链接还原:DOI 前缀 10.1038/ 的映射回 https://www.nature.com/articles/<suffix>链接仍直达 nature.com),其余前缀走 https://doi.org/<doi>
    • 摘要:对排序后 TOP count*2 篇的 PMID 一次性 efetchretmode=xml&rettype=abstract),正则切 <PubmedArticle> 块提取 <ArticleTitle> / <AbstractText>(多段拼接)/ <Journal><Title> / <PubDate> / <ELocationID EIdType="doi">
  4. 面板会标注本次来源(「来源:Nature 实时」/「来源:PubMed 镜像」),并把源切换原因写入响应(sourceError)展示在面板顶部提示条。

规避反爬的主动手段:浏览器 UA、请求间隔(默认 1.5s)、单次请求超时、失败重试 + 退避、翻页上限、仅在简介不足时抓文章页(减少请求量)、每日数据缓存(同一天不重复抓取)。

4.3 影响因子优先排序

数据if-data.js):~90 种期刊的近似 JCR 影响因子(主要 2023 版),覆盖 Nature 旗舰刊、Nature 研究子刊、Nature Reviews 系、npj 系,以及 nature.com 托管的 Springer Nature/BMC 高 IF 期刊(Signal Transduction and Targeted Therapy 40.8、Cell Research 28.1、Molecular Cancer 27.7、Genome Biology 10 等)。

名称归一化lowercase → 去非字母数字(含 & 与空格)→ 去开头 "the"。因此 nature.com 的 Communications Biology 与 PubMed 的 Nature reviews. Molecular cell biology 都能命中同一表项。

排序规则rankRows):

sort((a, b) =>
  (b.journalIf - a.journalIf) ||              // ① IF 降序("影响因子为优先")
  b.pubDate.localeCompare(a.pubDate) ||       // ② 同 IF 按发表时间新序
  a.title.localeCompare(b.title))             // ③ 稳定兜底

未收录期刊 IF 记为 0(排在所有已知期刊之后);卡片上 IF 未知时显示 IF —。数值仅作排序与展示,非官方授权数据。

4.4 内容简介(摘要抓取链)

  • 数据源 A:先取搜索页自带 snippet;当 snippet 缺失或长度 < 60 字符时,才去抓文章页 Abstract——定位 id="Abs1-content" 开标签之后的内容,截到 </section> 前,stripTags 去标签、折叠空白;长度 < 40 视为无效。抓取按 requestDelayMs 间隔串行(礼貌限速)。
  • 数据源 Befetch 一次取回 TOP 候选的全文摘要(PubMed 摘要覆盖率 ~100%)。
  • 最终兜底abstract || snippet || '(暂无简介,请点击标题查看原文)'
  • 客户端对超过 140 字的摘要做三行截断 + 「展开简介 / 收起简介」切换。

4.5 每日 3 篇与缓存

  • 存储:单 JSON 文件(config.storageFile,默认 $DSH_HOME/storages/nature-papers.json),结构见存储格式。写入为原子操作(先写 .tmp 再 rename);解析失败时旧文件改名 .bak 后重建。
  • 生成时机
    1. GET /today 首次请求当天数据时(惰性生成,含真实爬取);
    2. 每日轮换定时器(每 30 分钟检查一次本地日期是否变化,跨天且当天无数据时后台预生成);
    3. 用户点「刷新」强制生成。
  • 幂等:同一天内 /today 恒定返回当天条目(缓存优先),不会因页面刷新而变;跨天自动换新。
  • 并发合并state.generating 持有进行中的生成 Promise,并发请求共享同一次生成,不会重复爬取。

4.6 历史记录与去重

  • 每次成功生成后,条目插入历史头部(按日期倒序),同日条目替换,上限 historyCap(400 天)。
  • 去重(永不重复推荐):候选池过滤掉历史中所有已推荐 URL;若过滤后不足 count 篇 → 放宽为仅排除近 30 天;仍不足 → 允许重复(取当前最优)。
  • 客户端「历史」视图按日期分组,点击日期展开当天卡片(TOP 编号、期刊、IF、标题链接、简介)。

4.7 实时刷新

  • POST /refreshgenerate(force=true)立即重新爬取,且把当天已有条目也计入排除(换选一批新论文)。
  • 失败返回 502 { ok:false, error },客户端展示错误 + 重试按钮。

4.8 右下角面板(客户端)

  • 挂载shell.overlay 槽位(list 型、root 作用域),注册 id nature-papersorder: 100
  • 状态机collapsed(收起为胶囊,localStorage 记忆)/ view(今日 ↔ 历史)/ loading / error / entry / history / expanded(摘要展开)/ exitState(退出确认)。
  • 每日自愈:窗口 focus 事件 + 每 10 分钟定时器检查「本地日期 ≠ 面板日期」→ 自动重新拉取 /today
  • 样式:全部走应用主题 CSS 变量(--dsw-alias-*)+ 兜底值,适配亮/暗色;样式以 <style data-plugin="dsh-nature-papers"> 注入,插件卸载时由 HMR 机制清理。

4.9 退出 Harness

  • 宿主端:POST /shutdown → 先返回 200 {ok:true}(让面板来得及显示最终状态),200ms 后调用 DSH 提供的 appExit 服务(ctx.get('appExit'),由 launcher 在启动时注入,走优雅关闭流程:dispose 插件树、关闭 HTTP 服务器、退出进程);appExit 不可用时回退 process.exit(0)
  • 客户端:底部「⏻ 退出 Harness」→ 第一次点击进入「⚠ 确认退出?」(4 秒未确认自动还原)→ 第二次点击 POST /shutdown 并显示「正在退出…」。

HTTP 接口规范

统一前缀 /plugins/dsh-nature-papers;响应 { ok: boolean, data?: any, error?: string }

方法路径说明错误码
GET/today今日推荐(当天首次请求触发实时爬取)502 上游失败;405 方法不符
GET/history全部历史(日期倒序)405
POST/refresh强制重爬并换选今日推荐502;405
GET/info运行状态:日期、历史天数、数据源、最近生成时间、最近错误405
POST/shutdown优雅关闭服务器进程405

/today 响应示例:

{
  "ok": true,
  "data": {
    "date": "2026-08-14",
    "papers": [
      {
        "rank": 1,
        "title": "Acquired resistance to the RAS(ON) multi-selective inhibitor …",
        "url": "https://www.nature.com/articles/s41591-026-04537-w",
        "journal": "Nature Medicine",
        "journalIf": 58.7,
        "journalIfKnown": true,
        "pubDate": "2026-08-11",
        "doi": "10.1038/s41591-026-04537-w",
        "summary": "Circulating tumor DNA analyses in 44 patients …",
        "openAccess": true,
        "source": "nature"
      }
    ],
    "sourceError": null
  }
}

配置项

字段默认说明
querybioinformatics biochemistryNature 搜索关键词(空格 = AND)
count3每天推荐篇数(1~10)
storageFile$DSH_HOME/storages/nature-papers.json历史存储路径
requestDelayMs1500抓取间隔(限速)
requestTimeoutMs25000单次请求超时
maxCandidates90候选池大小(最新 N 篇中按 IF 择优)
historyCap400历史保留天数

存储格式

{
  "history": [
    {
      "date": "2026-08-14",
      "papers": [
        {
          "rank": 1,
          "title": "…",
          "url": "https://www.nature.com/articles/…",
          "journal": "Nature Medicine",
          "journalIf": 58.7,
          "journalIfKnown": true,
          "pubDate": "2026-08-11",
          "doi": "10.1038/…",
          "summary": "…",
          "openAccess": true,
          "source": "nature"
        }
      ]
    }
  ]
}

限速、容错与反爬规避

机制实现
请求间隔翻页、文章页抓取间延迟 requestDelayMs
超时每请求 AbortSignal.timeout(requestTimeoutMs)
重试网络失败重试 1 次,退避 1.2s
反爬检测Client Challenge 特征串 + 结果行缺失双重判定
双源容灾nature.com 失败 → PubMed;双源都失败 → 502 + 明确错误文案
请求量控制同一天缓存;仅当 snippet 不足才抓文章页;PubMed 摘要一次 efetch 批量获取
存储安全原子写(tmp+rename);损坏自动 .bak 重建
并发生成 Promise 合并(in-flight 共享)
生命周期所有路由/定时器注册在 ctx.effect 内,插件卸载自动清理

已知限制与局限

  • 影响因子为近似 JCR 参考值(主要 2023 版),仅用于排序与展示,非官方授权数据;数值会随时间过时。
  • nature.com 可能对高频访问下发 Client Challenge,此时自动使用 PubMed 镜像(见 4.2),面板会标注来源。
  • 接口仅在本地回环暴露、无鉴权(与 DSH 其他 /plugins 路由一致)。
  • 代码热更新受限cordis.patch.ymlwatchUserPatches 监视,但该热加载在实测中不稳定(BOM 编码、文件删除、chokidar 精确文件监视失效等都会导致其停止响应),因此插件代码(lib/*.js)修改后必须重启 dsh web(见运维一节);条目级配置改动同样建议重启后生效。
  • 面板为固定位置浮层(不可拖拽);与其它注册到 shell.overlay 的浮层按注册顺序叠加。

运维:安装 / 更新 / 启停 / 卸载

以下命令均在仓库根目录下执行(powershell -ExecutionPolicy Bypass -File .\xxx.ps1)。 脚本自动解析 $DSH_HOME(环境变量,缺省 ~/.dsh);dsh 启动器自动探测(PATH 或 npx 缓存,可用 -DshBin 指定);端口可用 -Port 指定(默认 3080)。不含任何本机硬编码路径。

# 安装 / 更新(同步代码 + 写入 patch 条目;服务器运行中会自动改为原地覆盖)
powershell -ExecutionPolicy Bypass -File .\install.ps1

# 卸载
powershell -ExecutionPolicy Bypass -File .\install.ps1 -Uninstall

# 启停(代码变更后需重启生效)
powershell -ExecutionPolicy Bypass -File .\stop-dsh.ps1
powershell -ExecutionPolicy Bypass -File .\start-dsh.ps1
powershell -ExecutionPolicy Bypass -File .\restart-dsh.ps1   # 杀旧→确认端口→起新→自检

# 面板「⏻ 退出 Harness」等价于 stop-dsh.ps1(走优雅退出)

诊断$DSH_HOME\restart-result.txt(重启自检)、$DSH_HOME\web-server.log / web-server.err.log(服务器日志)、GET /plugins/dsh-nature-papers/info(运行状态)。

二次开发建议:爬虫核心 scraper.js 不依赖 Cordis,可用 node test-scraper.mjs 独立验证;改完 lib/* 后运行 install.ps1 并重启即可。

REPOSITORY SIGNALS

보안 및 설치 증거

이 점수는 공개 저장소 메타데이터와 이 사이트에 등록된 설치 증거에만 기반하며, 코드 보안 감사와 다릅니다.

출처 추적 가능

공개 플러그인 카탈로그에서 왔으며, 공개 GitHub 저장소로 연결됩니다.

라이선스

저장소가 MIT 라이선스를 선언했습니다.

유지보수 활동

최근 180일 내 코드 업데이트가 있습니다.

설치 증거

재현 가능한 정확한 설치 메타데이터가 아직 등록되지 않았습니다. 저장소 설명에 따라 직접 확인하세요.

설치 라이프사이클 스크립트

검사한 패키지 메타데이터에 설치 라이프사이클 스크립트가 선언되지 않았습니다.