关于 fulltext-article-downloader
fulltext-article-downloader 可通过 DOI、arXiv、PMC 或 OpenReview 标识符获取研究论文全文。研究人员和 AI Agent 可通过 Python API、命令行或 MCP 服务使用它;它会尝试多个来源并核验文件是否对应论文记录。
主要功能
- 01从多个论文来源下载
- 02自动切换检索方式
- 03根据论文标题核验 PDF
- 04并发批量下载
- 05可选获取补充文件
适用场景
- 01通过 DOI 或存储库 ID 获取论文
- 02批量下载论文并记录结果
- 03向 AI Agent 提供论文检索工具
MCP 相关
可选的 fulltext-mcp 服务向 MCP 客户端提供 get_paper 和 get_papers 工具,并使用与命令行相同的凭据。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
uvx fulltext-article-downloaderUNPAYWALL_EMAILContact email for Unpaywall and CrossrefFULLTEXT_OUTPUT_DIRFolder for downloaded files (default ./papers)WILEY_API_KEY密钥Wiley TDM tokenELSEVIER_API_KEY密钥Elsevier API keySPRINGER_API_KEY密钥Springer Nature API keySEMANTIC_SCHOLAR_API_KEY密钥Semantic Scholar API key本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
工具
2收录的工具列表 · 更新于 2 周前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| tools | any | 否 | |
| identifier | string | 是 | |
| output_dir | string | 否 | |
| supplements | boolean | 否 |
详细介绍
fulltext-article-downloader
fulltext-article-downloader 是一个 Python 包,用于以编程方式下载研究文章的全文,支持通过 DOI、arXiv id、PubMed Central id 或 OpenReview id 获取。它按回退顺序串联出版商 API、开放获取索引和存储库,检查返回的内容是否确实为所请求的文章,并可从 Python、命令行使用,或由 AI Agent 通过 MCP 服务或 Claude Code 技能调用。
视频教程:https://youtu.be/fTtc4QWMYzE
功能特性
- 多种检索方式 – Elsevier、Wiley 和 Springer Nature API、CrossRef TDM 链接、Unpaywall、Europe PMC、OSTI(DOE 资助文章的录用稿)、Semantic Scholar 的开放获取索引、arXiv、ChemRxiv、bioRxiv/medRxiv、Zenodo、MDPI 的 CDN,以及对缺乏便捷 API 的出版商(PLOS、eLife、Cambridge、APS)直接抓取。
- 自动回退逻辑 – 该包根据 DOI 的出版商选择最佳方式;若一种失败,会自动尝试下一种。
- 验证 – 每个 PDF 都会与文章标题进行核对,支持信息文件和仅有摘要的记录会被拒绝,因此返回的文件就是你所请求的论文。
- 诚实的结果 – 每次下载都会报告是哪种途径产生了该文件,并在文件为预印本或录用稿而非出版商正式发表版本时附带说明。
- 可配置的工具顺序 – 可按出版商配置方式顺序;默认配置覆盖大多数主要出版商和预印本服务器。
- 批量下载 – 支持并发下载并强制执行出版商速率限制,提供
tqdm进度条,以及记录哪个工具成功或某个标识符为何失败的文件日志。 - 便捷的 API 密钥管理 – 通过环境变量或交互式
fulltext-config脚本存储凭据。 - 四个入口,一个引擎 – Python API、
fulltext-download命令行、面向任意 MCP 客户端的fulltext-mcp服务,以及带有现成技能的 Claude Code 插件。
1. 安装
pip install fulltext-article-downloader
可选附加项可启用更多途径和 MCP 服务:
| 附加项 | 新增内容 |
|---|---|
mcp | fulltext-mcp 服务(fastmcp) |
tls | 针对拒绝普通 HTTPS 客户端的主机,提供 Chrome TLS 指纹回退(curl-cffi) |
springer | Springer Nature 开放获取 XML 途径(sprynger) |
preprints | 通过 paperscraper 下载 bioRxiv/medRxiv |
aps | 复用浏览器登录 cookie 的 APS 途径(browser-cookie3) |
all | 上述所有内容 |
tls 和 aps 都是通过让请求看起来更像你自己的浏览器而非脚本:tls 针对拒绝普通 HTTPS 客户端的主机匹配 Chrome 的 TLS 指纹,而 aps 复用你已登录的 APS 会话 cookie。二者都不会打开你未获授权的内容,但都比普通 API 客户端更进一步,因此在启用前值得对照你所在机构的协议进行核查。默认安装不包含二者;all 包含它们。
pip install "fulltext-article-downloader[mcp,tls]"
如需开发,请克隆仓库并运行 pip install -e ".[dev,all]"。之后请务必配置你的安装(见下一节)。
2. 配置(API 密钥与邮箱)
所有凭证均为可选;每一项都会解锁一条路径。在没有密钥且不在校园网内的情况下,可预期的结果是:开放获取论文、预印本和 DOE 资助的稿件可以正常工作,而大多数付费墙文章会失败。
| 服务 | 环境变量 | 获取密钥的位置 |
|---|---|---|
| Unpaywall 和 Crossref 联系邮箱(你自己的地址) | UNPAYWALL_EMAIL | (填写你的邮箱地址) |
| Elsevier API | ELSEVIER_API_KEY | https://dev.elsevier.com |
| Wiley TDM API | WILEY_API_KEY | https://onlinelibrary.wiley.com/library-info/resources/text-and-datamining |
| Springer Open Access API | SPRINGER_API_KEY | https://dev.springernature.com |
| Semantic Scholar(可选;可提高速率限制,并启用标题搜索,从而找到那些 DOI 记录中没有 PDF 的论文的 arXiv 副本) | SEMANTIC_SCHOLAR_API_KEY | https://www.semanticscholar.org/product/api(免费,几天内通过邮件批准) |
UNPAYWALL_EMAIL 只会发送给 Unpaywall 和 Crossref,这两个服务要求 API 用户提供联系地址;Crossref 会从更快的“polite”池中处理带有该地址的请求。密钥和邮箱都保留在你的机器上。
设置这些环境变量,或运行交互式辅助脚本:
fulltext-config
该脚本将密钥存储在 ~/.fulltext_keys 中,导入时会自动加载。如果缺少必需的密钥,相应的工具会被跳过,下载器会回退到其他方法。出版商密钥只有在密钥或网络具有权限时才会返回付费墙内容;该包会检测被截断或仅有摘要的响应,并继续尝试其他方式。
3. 用法
标识符
在需要标识符的任何地方,以下任一形式均可接受:
- DOI:
10.1021/jacs.3c13302、https://doi.org/10.1021/jacs.3c13302、doi:10.1021/jacs.3c13302 - arXiv:
2310.19377、arXiv:2310.19377、https://arxiv.org/abs/2310.19377、cond-mat/9712061、10.48550/arXiv.2310.19377 - PubMed Central:
PMC6561843 - OpenReview:
fNyXCCZ0g6
命令行界面(CLI)
fulltext-download <ID> [<ID> ...] [-o DIR] [--tools a,b,c] [--workers N] [--no-check] [--log-file FILE]
fulltext-download 10.1371/journal.pone.0171501 -o papers
fulltext-download 10.1021/jacs.3c13302 arXiv:1710.10324 PMC6561843 -o papers --workers 4
该命令会为每个标识符打印一个 JSON 对象,并且只有当所有下载都成功时才以 0 退出:
[
{
"identifier": "10.1021/jacs.3c13302",
"success": true,
"path": "papers/10.1021_jacs.3c13302.pdf",
"source": "osti",
"note": "OSTI accepted manuscript, not the publisher's version of record",
"error": null,
"attempts": [],
"supplements": []
}
]
原始形式 fulltext-download <DOI> <OUTPUT_DIR> [<FILENAME>] 仍然可用。
Python API
fetch 返回与 CLI 打印相同的结构;fetch_many 会并发下载一个列表:
from fulltext_article_downloader import fetch, fetch_many
r = fetch("10.1371/journal.pone.0171501", "papers")
if r["success"]:
print(r["path"], r["source"], r["note"])
else:
print(r["error"]) # every route tried, with its reason
rs = fetch_many(["10.1002/advs.201900808", "10.48550/arXiv.2207.03928"], "papers", workers=4)
之前的函数保持不变:download_article(doi, output_dir, ...) 返回路径或抛出异常,bulk_download_articles(dois, output_dir, log_file=..., sleep=..., workers=...) 返回路径字典或 "ERROR: ..." 字符串,并带有进度条。
它们共有的选项:output_filename(单次下载)、tools(覆盖出版商默认值的路径名称列表)、log_file(追加下载日志),对于 fetch 还有 check=False 以跳过验证,以及 skip_existing=False 以重新下载已存在的文件。
补充文件
fetch(..., supplements=True)、fetch_many(..., supplements=True)、fulltext-download --supplements 以及 MCP 工具的 supplements=true 还会获取文章的补充文件(支持信息、数据表、视频)。它们是来自不同位置的独立文件,因此会与文章一起保存为 <name>_si1.pdf、<name>_si2.xlsx、……,并列在结果的 supplements 中。来源:ChemRxiv 和 Elsevier API、Europe PMC 为 PMC 文章提供的补充文件包,否则来自文章的落地页(Springer Nature、Wiley、bioRxiv、ACS、RSC、PLOS 等会在那里提供链接;大多数出版商无需订阅即可提供补充文件)。默认关闭,因为每篇文章会多消耗一次请求;缺少补充文件绝不会导致下载失败。
MCP 服务(供 Agent 使用)
fulltext-mcp 暴露两个工具:get_paper(identifier, output_dir="", tools=None, supplements=False) 和 get_papers(identifiers, output_dir="", max_workers=4, supplements=False),返回上面展示的结构。它需要 mcp extra,并读取与命令行相同的键。FULLTEXT_OUTPUT_DIR 设置当调用未提供输出目录时文件的存放位置(默认 ./papers)。
Claude Code:
claude mcp add fulltext-article-downloader -- uvx --from "fulltext-article-downloader[mcp]" fulltext-mcp
任何其他 MCP 客户端,在其服务配置中:
{
"mcpServers": {
"fulltext-article-downloader": {
"command": "uvx",
"args": ["--from", "fulltext-article-downloader[mcp]", "fulltext-mcp"],
"env": { "UNPAYWALL_EMAIL": "[email protected]", "FULLTEXT_OUTPUT_DIR": "/abs/path/papers" }
}
}
}
uvx 会在首次使用时从 PyPI 将包拉取到隔离环境中,因此无需事先安装任何内容。该服务也已在官方 MCP 注册表中登记为 io.github.computron/fulltext-article-downloader。
Claude Code 插件与技能
此仓库同时也是一个 Claude Code 插件。它会安装一个技能,教会 Claude 何时以及如何使用 fulltext-download,以及上面的 MCP 服务:
/plugin marketplace add computron/fulltext-article-downloader
/plugin install fulltext-article-downloader@fulltext-article-downloader
在 Claude Code 中,仅技能本身(不含 MCP)就足够了:它运行命令行并读取 JSON。MCP 服务面向无法运行 shell 命令的客户端,以及其他 Agent 框架。
4. 失败与工具
失败示例
许多文章并非开放获取,出版商明确限制或不鼓励文本和数据挖掘。以下示例预期会失败:
fulltext-download 10.1109/GROUP4.2007.4347715 -o papers
error 字段列出尝试过的每条路径以及失败原因。失败几乎总是意味着文章处于付费墙之后且没有开放获取副本,或者某台主机阻止了自动化访问。
如果你看到类似 Failed to load APS cookies 的错误,请确保你运行 Python 所用的应用程序拥有完整的磁盘访问权限。
验证
以 %PDF- 开头的文件并不能证明什么:开放获取索引偶尔会将某个 DOI 映射到不相关的文档,而补充信息文件也可能带有文章的标题。在每条路径之后,该包会提取前两页并检查 Crossref 标题是否存在,拒绝以 Supporting Information 标题开头的文件,并拒绝不包含正文的 Elsevier XML 记录。被拒绝的文件会被删除,然后尝试下一条路径。--no-check / check=False 会关闭此功能。
方法与回退逻辑
该工具由多个子工具组成,旨在支持各种出版商。工具顺序取决于出版商。
| 出版商 / 来源 | 默认工具顺序 |
|---|---|
| Elsevier | unpaywall → elsevier(有权限时用 PDF,否则用 XML)→ europepmc → osti → semantic |
| Springer / Nature | springerpdf(nature.com、SpringerLink)→ unpaywall → europepmc → springeropen(XML)→ osti → semantic |
| Wiley | wiley → unpaywall → europepmc → osti → semantic |
| APS | aps → unpaywall → crossref_tdm → europepmc → osti → semantic |
| ACS、RSC、AIP | unpaywall → europepmc → crossref_tdm → osti → semantic |
| PLOS | plos → unpaywall |
| eLife | elife → unpaywall |
| Cambridge | cambridge → unpaywall → europepmc → osti → semantic |
| arXiv | arxiv → unpaywall |
| ChemRxiv | chemrxiv → paperscraper → unpaywall |
| bioRxiv、medRxiv | biorxiv → unpaywall → paperscraper |
| MDPI | mdpi → unpaywall → europepmc → semantic |
| Zenodo | zenodo |
| 其他 | unpaywall → europepmc → crossref_tdm → osti → semantic → elsevier |
arXiv、PMC 和 OpenReview id 会直接交给 arxiv、pmc 和 openreview(OpenReview 目前会对自动请求返回一个 challenge;此时该路由会说明这一点)。pmc 会获取 Europe PMC 的 PDF 渲染版本,而当该端点拒绝时(它会对连续请求大量文章的宿主进行限流),则从 Europe PMC 的 REST 服务或 NCBI 的 efetch 获取全文 JATS XML,后者也提供作者手稿(NCBI_API_KEY 是可选的,可提高 NCBI 的速率限制)。 |
不太明显的工具做什么:
elsevier会先请求 PDF,只有当 API key 有权获取完整 PDF 时才保留它;否则 Elsevier 会以 HTTP 200 响应,并返回一个只包含文章第一页的 PDF,因此该工具会丢弃它,转而获取全文 XML,并在其旁边写入一份 markdown 渲染结果。仅含摘要的 XML 会被拒绝。返回的路径始终带有实际写入格式的扩展名。crossref_tdm会尝试 Crossref 中注册的每一个全文链接,包括 APS、ACS 和 RSC 使用的unspecifiedcontent-type 链接;在有权访问的网络上,它们会返回 PDF。europepmc会下载 PMC 托管的开放获取文章,以及 Europe PMC 中该 DOI 记录所列的仓库副本(通常是作者手稿)。当记录显示文章的全文在 PMC 中时(根据资助方要求存放的作者手稿),它会获取 PMC 副本:PDF 渲染版本,或者在该端点拒绝时获取 JATS XML。osti会为 DOI 查询 OSTI API,并下载 DOE 资助的文章在发表约一年后在 osti.gov 上获得的 accepted manuscript。它不需要凭据;仍处于 embargo 期的记录没有全文,该工具会继续处理下一个。semantic会下载 Semantic Scholar 为该 DOI 索引的开放获取 PDF,大多是订阅文章的 arXiv 和机构仓库副本。unpaywall和semantic也接受仓库落地页:当索引列出的是页面而不是文件时(HAL、DSpace、Columbia Academic Commons),该工具会读取页面为 Google Scholar 携带的citation_pdf_url标签并下载它。chemrxiv通过 Cambridge Open Engage API 访问,该 API 可以从 chemrxiv.org 本身屏蔽的宿主访问。该 API 只能解析某个条目最新版本的 DOI,因此基础 DOI 或较旧版本会用版本后缀重试。biorxiv会询问 bioRxiv API 该 DOI 位于哪个服务器(bioRxiv 或 medRxiv)以及哪个版本是当前版本,然后获取该 PDF。请求会限速(该站点在突发请求后以 429 和 100 秒 Retry-After 响应),其返回的暂时性 503 会重试;当 API 本身在限流时,会在两个服务器上尝试不带版本的 URL,该 URL 会重定向到当前版本。mdpi会根据 Crossref 记录在 MDPI 的 CDN(mdpi-res.com)上构建文章路径;www.mdpi.com 本身会拒绝来自云服务商地址范围的请求。zenodo会下载 Zenodo 记录(10.5281 DOI)所附的 PDF;concept DOI 会解析到最新版本。wiley也用于 Wiley Online Library 上托管的学会期刊(AGU 等):Crossref 会在 wiley.com 上列出它们的全文链接,TDM API 会提供这些内容。同样,对于 Crossref 链接指向 Elsevier 的期刊,会添加elsevier,并且它被放在默认列表的最后,因为 Elsevier 的 API 也以其自身出版商名称提供其分发的学会期刊(ASH 的 Blood);非 Elsevier 的 DOI 只会产生一次快速的 404。semantic还会在记录未列出 PDF 时,下载记录的externalIds中所列的 arXiv 版本,并且在设置了SEMANTIC_SCHOLAR_API_KEY时,按标题搜索同一论文的第二条记录(搜索端点在没有 key 时会返回 429)。请求之间间隔一秒,这是 Semantic Scholar 的限制。 下载时会发送浏览器 User-Agent,对于仅向非浏览器客户端提供 PDF 的仓库,会用普通 User-Agent 重试;若安装了tls额外依赖,还会再以 Chrome TLS 指纹重试一次。Wiley 请求被限制为每 10 分钟 30 次(公布的限制是 60,但从大约 35 次起 API 就会返回 HTTP 500),Crossref 请求限制在其 polite-pool 上限内,瞬时的 429/5xx 响应会重试一次。
返回预印本或已接受稿件的路由(arxiv、chemrxiv、biorxiv、osti、semantic,以及来自 unpaywall 和 europepmc 的仓库副本)会在结果中设置 note。参见 downloader.py 中的 PUBLISHER_TOOL_MAP。
提示 – 基于抓取的方法(
springerpdf、elife、cambridge等)可能因网站布局变化或访问限制而失效;大规模下载时请优先使用官方 API 和 Unpaywall。
回归测试集
benchmark/ 中存放了 178 个已知结果的标识符,以及一个用于检查候选版本的运行器:
python benchmark/run_regression.py 会打印 known_good、needs_institution 和 expected_fail
标识符中成功下载的数量,并在某个 known_good 标识符失败时以非零状态退出。参见 benchmark/README.md。
自定义工具序列
from fulltext_article_downloader import fetch
fetch("10.1017/S0885715624000484", "papers", tools=["unpaywall", "cambridge"]) # override default order
在运行时覆盖:
from fulltext_article_downloader import PUBLISHER_TOOL_MAP
PUBLISHER_TOOL_MAP["Elsevier BV"] = ["elsevier", "unpaywall"]
5. 许可证与免责声明。
BSD 3-Clause。参见 LICENSE 文件。
仅将本工具用于你有合法权利访问的内容。请遵守出版商条款和版权法。本工具不使用 Sci-Hub 或任何类似网站,仅检索你自己的订阅、API 密钥和开放获取许可已经允许的内容;可选的 tls 和 aps 路由会像浏览器一样呈现你的请求,如安装部分所述。作者不对滥用行为负责。
由 computron 凭感觉(ChatGPT 4.0)和咖啡因快速编写;由 Xu Huang 使用 Claude 扩展。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。