Community연구 & 데이터 분석github.com

PMC / OA 文献 PDF 获取

开放获取生物医学文献 PDF 下载工具,支持离线 Proof-of-Work 求解,自动处理 PMC 的 403/404 及 reCAPTCHA 挑战。

OA 文献 PDF 获取란 무엇인가요?

该技能专为 AI 代理设计,用于从 PubMed Central (PMC) 及欧洲 PMC 下载开放获取 (OA) 生物医学文献的全文 PDF。核心亮点在于实现了 PMC 的离线 Proof-of-Work (PoW) 挑战求解,避免了传统爬虫遇到 reCAPTCHA 时无法处理的困境。技能提供了完善的降级策略:优先使用 EuropePMC 的结构化全文 XML,其次通过 Unpaywall 定位 OA PDF 直链,再调用内置 PoW 求解脚本,最后才尝试出版社官网直链或浏览器打印为 PDF。此外,它还特别强调了机构订阅场景下的合规使用(禁止批量下载),并详细指导了 PDF 文件名动态解析(利用 citation_pdf_url 元数据)等关键细节,确保下载成功率。支持通过 `python3 scripts/pmc_pdf.py <PMCID> <输出路径>` 命令一键使用。

지원 대상~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/GreenWich-art/agent-skills/tree/HEAD/skills/pmc-oa-pdf-fetch

Installed? Explore more 연구 & 데이터 분석 skills: affaan-m/uspto-database, affaan-m/scholar-evaluation, affaan-m/literature-review · View all 6 →

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

OA 文献 PDF 获取은(는) 무엇을 하나요?

适用前提

只用于**开放获取(OA)**文献(CC BY / CC BY-NC / CC BY-NC-ND 等)。不要用于绕过付费墙获取订阅制论文——那属于规避版权保护。判断 OA 状态:Unpaywall 返回 is_oa: true,或 EuropePMC 的 isOpenAccess: Y。

机构订阅场景(重要补充)

用户所在学校/单位订阅了出版商数据库时,人工单篇下载在授权范围内完全合规,但需注意:

  • 校园网 / 机构 IP 段内:出版商认 IP 不认人,降级链第 5 级(出版社直链)通常直接返回 200,Cloudflare 也不会拦截——此时本 skill 的现有管线可以直接拿到订阅内容,无需任何登录逻辑。
  • 校外访问:优先使用学校提供的系统级 VPN(对脚本透明,配置一次即可);WebVPN(URL 改写型代理)因各校改写规则不同、且需携带会话 Cookie,本 skill 不做支持。
  • 不要写 Shibboleth / OpenAthens 自动登录:需要本地存储统一身份认证凭证,属安全隐患;且各校 IdP 流程差异大,通用实现不可行。
  • 批量下载红线:几乎所有出版商的机构许可都区分「人工单篇下载」与 systematic/bulk downloading。即使有订阅,脚本批量抓取也违反许可条款,可导致全校 IP 段被封禁。确有大规模全文挖掘需求时,应申请出版商的 TDM(文本挖掘)API(如 Elsevier TDM API、Springer Nature Meta API),走官方配额通道,而不是用本 skill 批量循环。

降级链(严格按顺序)

优先级途径命令 / 端点说明
1EuropePMC 结构化全文https://www.ebi.ac.uk/europepmc/webservices/rest/{PMCID}/fullTextXML最稳定。用于提取精确到二级标题的全文结构。返回 JATS XML
2Unpaywall 定位 OA 位置https://api.unpaywall.org/v2/{DOI}[email protected]读 oa_locations[].url_for_pdf,直接给出 PDF 直链
3PMC PoW 求解下载scripts/pmc_pdf.py <PMCID> <out.pdf>见下文。获取正文 PDF 的主力方案
4EuropePMC 补充材料https://www.ebi.ac.uk/europepmc/webservices/rest/{PMCID}/supplementaryFiles返回 ZIP:原始图片(gr1…=Figure 1…)+ 补充材料 PDF(mmc1.pdf)
5出版社直链各出版社 .../article-pdf/...通常 403(Cloudflare)。最后才试

已确认失效的端点(不要浪费时间)

  • …/rest/{PMCID}/fullTextPDF → 404(已废弃)
  • …/rest/{PMCID}/fulltextRepo → 403
  • https://europepmc.org/articles/{PMCID}?pdf=render → 403
  • https://europepmc.org/backend/ptpmcrender.fcgi?accid=…&blobtype=pdf → 403
  • https://www.ncbi.nlm.nih.gov/pmc/utils/oa/oa.fcgi?id=… → 404(OA service 已迁移)
  • ashpublications.org 文章页在无头浏览器中停留于 Cloudflare「请稍候…」挑战页,不可用

★ 先决条件:PMC 的 PDF 文件名不固定,必须先解析

https://pmc.ncbi.nlm.nih.gov/articles/{PMCID}/pdf/<文件名>.pdf 中的文件名随期刊与年份变化,硬编码 main.pdf 在多数情况下会 404。

实测期刊真实文件名
Am J Hematolmain.pdf
Blood Advancesmain.pdf
HemaSphereHEM3-10-e70338.pdf
Am J HematolAJH-101-1790.pdf
Liver InternationalLIV-46-0.pdf
Haematologica111300.pdf(卷 111 + 起始页 300,省略期刊缩写)
Blood(NIH 作者稿)nihms-2192199.pdf

解析方法(按优先级;实测多例全部命中第 1 条)

  1. 文章页 <meta name="citation_pdf_url" content="https://pmc.ncbi.nlm.nih.gov/articles/{PMCID}/pdf/XXX.pdf"> ← 最可靠
  2. grep -oE 'href="[^"]*?/pdf/[^"]+?\.pdf"' 取第一个命中
  3. 兜底 pdf/main.pdf

命名规律参考(不可依赖,仅用于人工判断是否解析正确):Wiley 系 OA 常见 <期刊缩写>-<印刷卷>-0.pdf(如 LIV-46-0.pdf);带文章号时为 <期刊缩写>-<卷>-<文章号>.pdf(如 HEM3-10-e70338.pdf);同刊常为 <缩写>-<卷>-<起始页>.pdf(如 AJH-101-1790.pdf);亦有「卷+起始页、无期刊缩写」变体(如 Haematologica 的 111300.pdf = 卷 111 + 起始页 300)。

抓文章页时务必丢弃 Cookie:用一个独立的、不保留 Cookie 的请求去读文章页,PDF 请求仍必须从全新 Cookie 会话发起。若把文章页产生的 ncbi_sid / ncbi_pinger 带到 PDF 请求上,会被直接升级为 reCAPTCHA(实测)。scripts/pmc_pdf.py 已按此实现。

核心方案:离线求解 PMC Proof-of-Work

原理

https://pmc.ncbi.nlm.nih.gov/articles/{PMCID}/pdf/<文件名>.pdf 会按风险策略在两种挑战页之间切换:

  • PoW 页(1817 字节,标题 Preparing to download ...)→ 可离线求解,这是我们要的通道;
  • reCAPTCHA 页(约 20 KB,标题含 reCAPTCHA)→ 无法离线求解。

触发 PoW 而非 reCAPTCHA 的关键:使用简约 UA,且不要在请求 PDF 之前访问文章页。

User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)

反例(会被升级为 reCAPTCHA,实测):

  • 完整 Chrome UA(…AppleWebKit/537.36 … Chrome/1xx.0.0.0 Safari/537.36)
  • 先 GET 文章页(携带 ncbi_sid / ncbi_pinger)再请求 PDF

PoW 算法(从 pow-*.js 反解,已确认)

PoW 页内嵌四个常量:POW_CHALLENGE / POW_DIFFICULTY / POW_COOKIE_NAME / POW_COOKIE_PATH。

  1. 求最小非负整数 nonce,使得 sha256(challenge + str(nonce)).hexdigest() 的前缀等于 '0' * difficulty;
  2. 设置 Cookie:<POW_COOKIE_NAME> = challenge + "," + nonce(路径为 POW_COOKIE_PATH);
  3. 携带该 Cookie 与 Referer: https://pmc.ncbi.nlm.nih.gov/articles/{PMCID}/ 重新请求 PDF 直链 → 应返回 200 与 Content-Type: application/pdf。

典型 difficulty = 4(期望约 65536 次哈希,本地亚秒级完成)。

一键脚本

# 推荐:自动解析真实 PDF 文件名(走 citation_pdf_url),再离线求解 PoW
python3 scripts/pmc_pdf.py PMC13575452 ./out.pdf

# 已自行解析出文件名时可直接指定,跳过文章页请求
python3 scripts/pmc_pdf.py PMC13575452 ./out.pdf --pdf-name LIV-46-0.pdf

# 静默模式(只输出结果行)
python3 scripts/pmc_pdf.py PMC13575452 ./out.pdf --quiet

脚本行为:先以简约 UA、丢弃 Cookie 地请求文章页解析真实 PDF 直链 → 再以全新 Cookie 会话冷请求该 PDF → 若直接得到 PDF 则保存;否则解析 PoW 常量、求解、回填 Cookie 重试。如需强制重取 challenge,重跑即可(脚本不落盘 Cookie,每次都是全新会话)。

★★ 两条必须记住的硬规则(实测血泪教训)

1. 第二个位置参数是输出文件全路径,不是目录。 传目录会在已经拿到 PDF 之后抛 IsADirectoryError: [Errno 21] Is a directory,前面那次 PoW 白解、那份 PDF 白拿。 ❌ pmc_pdf.py PMC13482240 --outdir /path/to/dir  ✅ pmc_pdf.py PMC13482240 /path/to/dir/xxx.pdf

2. PMC 的 PDF 通道有「一次机会」特性。 首次冷请求基本都能走通 PoW 并拿到真 PDF;紧接着对同一 PDF 再请求一次,几乎必然升级为 reCAPTCHA(不是「换 UA 就好」的普通限流)。因此第一次就要把输出路径写对,绝对不要「先试跑看看」。实测:首轮 status=200 type=application/pdf bytes=23970819,数秒后重跑同一 URL 即变为 type=text/html bytes=21329(reCAPTCHA 挑战页)。一旦浪费掉这次机会,直接跳到下一节的「出版社官网降级路线」,不要在 PMC 上反复重试。

故障排查

现象原因处置
返回 HTML 且含 POW_CHALLENGE进入了 PoW 通道(正常)交给脚本求解
返回 HTML 且含 recaptcha被升级为 reCAPTCHA换简约 UA、清会话 Cookie、稍等重试;仍失败则改用途径 4/5
404 / 「Article not found」PDF 文件名猜错了回到文章页解析 citation_pdf_url,不要硬编码 main.pdf
nonce 长时间不收敛difficulty 被调高打印 difficulty 判断;>5 时考虑异步或多进程求解
求解成功但 PDF 仍是 HTMLCookie 域 / 路径不匹配确认 Cookie 域为 pmc.ncbi.nlm.nih.gov、路径取 POW_COOKIE_PATH
IsADirectoryError: Is a directory把输出参数当成了目录第二参数是输出文件全路径。此时 PDF 其实已经拿到了,只是没落盘——不要立刻重跑(会触发 reCAPTCHA),先改对路径,若已升级则直接走出版社官网路线
首次成功、第二次立刻 reCAPTCHAPMC 对同一 PDF 路径的「一次机会」限流见上文硬规则 2;放弃 PMC,走出版社官网降级路线
citation_pdf_url 返回 -mmc1.pdf该文 PDF 未入库,解析到的是补充材料Blood 等刊常见「有 JATS 全文但正文 PDF 未入库」。立刻放弃 PMC 路线,不要拿补充材料冒充正文(实测)

★ 存在 IP 级限流(实测) 短时间内对 PMC 重复请求 PDF(例如连续下载多篇)后,即使使用正确的简约 UA,也会被直接升级为 reCAPTCHA,且等待 45 s 仍不恢复。表现为「首次成功、随后全部失败」。 处置: ① 批量下载时在两次请求之间留出足够间隔;② 一旦进入 reCAPTCHA 状态,不要反复重试(只会延长封禁),改为先完成其他工作,或改用途径 4(supplementaryFiles)与出版社直链;③ 若确有多篇需求,优先按需下载而非批量预热。

★★ 降级路线:PMC 被 reCAPTCHA 卡死时改走出版社官网(实测有效)

当 PMC 直链两次均被升级为 reCAPTCHA(IP 级限流,等待后仍不恢复)时,若目标刊是全 OA 刊,走出版社官网比继续重试 PMC 更可靠:

UA="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)"
# 1) DOI 解析 → 观察最终落到哪个出版社文章页
curl -s -o /dev/null -w "final: %{url_effective}\nHTTP: %{http_code}\n" -A "$UA" -L "https://doi.org/<DOI>"
# 2) 在文章页解析真实 PDF 直链
curl -s -A "$UA" "https://<publisher-article-page>" | grep -oiE '<meta name="citation_pdf_url"[^>]*>|href="[^"]*\.pdf[^"]*"' | sort -u | head
# 3) 带 Referer 直取(出版社几乎不校验 Referer,但带上更稳)
curl -sL --retry 3 -A "$UA" -e "$ARTICLE_PAGE" -o "$OUT" "$PDF_URL"

★★ 出版社页被 Cloudflare 完全拦死时:用浏览器「打印为 PDF」(实测有效)

ashpublications.org(ASH 系期刊)本轮出现 Cloudflare 完全拦截,此前「等 10 s 再 open」的经验未能复现。有效替代路径:

  1. 打开 PMC 全文页(非 PDF),绕过出版社站点
  2. 用浏览器工具打印该页为 PDF:agent-browser pdf
  3. reCAPTCHA 首次弹出时再执行一次 open 即可通过

判定要点:目标刊属于 ASH / ScienceDirect 一类强 Cloudflare 防护时,不要在 curl 上反复重试——成功率低且会加深封禁,直接切浏览器通道。

  • 已验证可行:Haematologica / Ferrata Storti —— doi.org/10.3324/haematol.2025.287698 → haematologica.org/article/view/12187 → haematologica.org/article/download/12187/78653 → 2.91 MB / 14 页。
  • 不可行:仍受 Cloudflare 类挑战拦截的出版社(ASH ashpublications.org、Wiley onlinelibrary.wiley.com/doi/pdfdirect/...、De Gruyter、Thieme)——这些只能回 PMC 通道或浏览器会话。
  • 前置判断:只有全 OA / Gold OA 刊才值得试这条路线(订阅刊会撞付费墙,禁止绕过)。

★ 完整性校验:大文件下载被中断会导致 xref 损坏

curl 取 PDF 时若被 SIGTERM / 超时中断,文件头仍是正常的 %PDF-1.6、体积也看似合理,但 pdfinfo 会报 Invalid XRef entry。因此下载后不能只看文件头与文件大小,必须同时满足:

head -c 8 "$OUT"                                  # %PDF-…
tail -c 32 "$OUT" | od -c | tail -3               # 应能看到 startxref … %%EOF
pdfinfo "$OUT" | grep -E "Pages|Page size"        # 页数应与「卷期页」推算一致

三者齐全才算完整;缺失则重新完整下载(加 --retry 3),不要拿损坏文件交差。

补充材料与图片

正文 PDF 受阻时,supplementaryFiles 端点仍通常可用,且内容往往正是随文图片与补充方法:

curl -sL -o sup.zip "https://www.ebi.ac.uk/europepmc/webservices/rest/PMC13049628/supplementaryFiles"
unzip -o sup.zip -d sup/

命名约定(Wiley / ASH 系):*-gr1…*-grN 对应 Figure 1…N,*-ga1 为图形摘要,*-mmc1.pdf 为补充材料。

使用浏览器工具时

只有在需要点击、登录或渲染 JS 页面时才动用 agent-browser。纯下载场景不要启动浏览器——PoW 可离线求解,启动 Chromium 只增加数百 MB 开销与失败面。若确需浏览器:

  • 必须先把可用的 node 加入 PATH(否则 daemon 启动超时);
  • 任务结束务必 agent-browser close,避免僵尸 daemon。

复核清单

  • 下载前确认目标文献为 OA(或确认当前处于机构订阅 IP 段内——此情形下出版社直链可直接用,但仍仅限人工量的单篇下载,禁止批量)
  • 从文章页 citation_pdf_url 解析出真实 PDF 文件名(不要硬编码 main.pdf)
  • 保存后校验文件头为 %PDF
  • 尾部校验 startxref / %%EOF(大文件被中断会留下头正常、xref 损坏的半成品;pdfinfo 能识别)
  • 核验页数:用 re.findall(rb'/Count\s+(\d+)', data) 或 /Type /Page 计数,不要相信 file out.pdf 的页数(macOS 上常误报为 "1 pages");也可用 mdls -name kMDItemNumberOfPages
  • 抽首末页核对内容(pdftotext -f 1 -l 1 / -f N -l N),确认不是补充材料或其它文章
  • 记录 PMCID / DOI / 落盘路径,便于后续复核
  • 未成功时如实说明失败原因,不要以补充材料或图片冒充正文 PDF

Individual skills in this repo

This repo contains 4 individual skills — each has its own dedicated page.

GreenWich-art/agent-skills

桌面 GUI 操作的统一编排入口。当用户要求操作一个只有图形界面的应用(改设置、点按钮、填表单、操作无 CLI/连接器的软件)时使用此 skill。提供四级能力:①路由决策——判断任务该走连接器、浏览器控制、Office 技能、命令行还是 computer use 桌面接管;②授权引导——检测并引导用户完成 macOS 辅助功能/屏幕录制权限授权,处理授权不生效等常见坑;③任务派发与验证——按目标/边界/失败处理三段式描述派发 GUI 任务,并以最终截图为准确认结果;④AX 兜底层——内置 axctl 工具做元素级无障碍读写(AXPress 语义点击,不碰鼠标不抢焦点),适用于 computer use 不可用或轻量场景。台前调度全场景实测(macOS 15 + 27.0.1 复检)。触发词:操控电脑、操作某个软件、点某个按钮、GUI 操作、电脑设置。

GreenWich-art/agent-skills

按学术论文规范(小三黑体一级标题/四号黑体二级/小四正文宋体1.5倍行距/三线表/中西文混排Times New Roman/统计量斜体) 批量重整 Markdown 或已有 docx 的格式。用户说"按学术格式排版""三线表""小三号黑体标题""1.5倍行距" "数字英文用Times New Roman""P值斜体"时使用。基于 python-docx 直接生成 docx,不走逐段插入。 不适用:高校课程论文/作业的字体字号约定(标准不同);党政机关公文国标 GB/T 9704 (又是另一套标准)。三套标准不可混用。

GreenWich-art/agent-skills

参考文献的 GB/T 7714-2015 著录规范化,以及 URL / DOI / PMID / PMC 链接的 可访问性批量核验与"假失效"识别。 触发场景: - 论文 / 综述 / 作业要交,需要核对参考文献格式 - "帮我按国标改一下参考文献" - 要交付一份文献清单,需要确认链接没死 - 已经有一堆 links,要批量验证哪些还能打开 含一个可复用脚本 `scripts/check_refs.py`,能自动判别 URL / DOI / PMID / PMC 并并发核验,且能区分「真死」与「被反爬」——后者不该判为失效。 不适用:从零生成一份带引文的正文(那是写作任务); Zotero 样式定制(见正文第六节,按需手工改 CSL)。

GreenWich-art/agent-skills

Local OCR using the macOS Vision framework. Triggers: OCR, 识别图片文字, 提取截图内容, 扫描件转文字, 图片转文字, 扫描版PDF转文字, read text from image/screenshot/photo/scanned PDF. Local-first and offline; prefer it over cloud OCR whenever data is sensitive or the machine is offline.

관련 스킬