学术论文 PDF 下载(绕过 Cloudflare / reCAPTCHA / POW)
> 验证于 2026-08-31:成功下载 npj Digital Medicine 论文正文(10MB)+ 补充材料(3.7MB)。核心脚本随附于 scripts/download_paper.py。
一、问题与根因
2025–2026 起,主流出版商对论文 PDF 加了多重反爬:
| 站点 | 拦截方式 | curl/urllib 表现 |
|---|---|---|
| Nature / npj / Springer | Cloudflare "Client Challenge"(JS 校验 + 指纹) | HTTP 303 无限重定向 |
| PMC (NCBI) | 先 POW(工作量证明)→ 后升级 reCAPTCHA | "Preparing to download" 或 "Checking your browser - reCAPTCHA" |
| Europe PMC | 中间层 520 错误 | 空响应/520 |
结论:纯 HTTP 客户端(curl/urllib/requests)几乎必然失败,因为反爬依赖浏览器端 JS 计算 + 真实浏览器指纹。
二、可用方案(按优先级)
✅ 方案 1:Playwright + 系统 Edge(推荐,已验证)
channel="msedge"+headless=True复用系统真实 Edge,指纹可信,能过 Cloudflare JS 校验- 打开文章页 → 从 DOM 提取
.pdf链接 →page.evaluate(fetch)带 cookie 抓取 PDF 字节 → 落盘 - 关键:PMC 的 reCAPTCHA 连 headless 也过不了,但 Nature/Springer 走 Cloudflare 的 JS challenge,headless Edge 能过——优先从 Nature 官方页抓 PDF。
⚠️ 方案 2:补充材料直链(media.springernature.com)
- 补充材料挂在
media.springernature.com/.../MediaObjects/xxx_MOESM1_ESM.pdf,通常无反爬,urllib 直接可下。 - 正文仍走方案 1。
❌ 不推荐:sci-hub 等镜像
- 版权与稳定性问题,仅作最后兜底。
三、SOP(步骤化)
1. 用 WebSearch/WebFetch 确认 DOI → 定位 Nature 文章页 URL
(如 https://www.nature.com/articles/s41746-025-02297-4)
2. 跑 scripts/download_paper.py,传入文章页 URL + 输出路径
(脚本自动:打开页 → 等 Cloudflare → 提取 .pdf → fetch 字节 → 落盘)
3. 校验:head -c 8 file.pdf 应输出 "%PDF-1.x"
4. 补充材料:从文章页 DOM 提取 media.springernature.com 的 esm 链接,urllib 直下
四、关键坑
- PMC 优先走不通:PMC 现在把 POW 升级成了 reCAPTCHA,headless 浏览器无法通过;别再在 PMC 上浪费时间,直接打 Nature 官方页。
- 等待 Cloudflare:
wait_until="domcontentloaded"后需time.sleep数秒让 JS challenge 跑完,再读 DOM。 - fetch 要带 cookie:
page.evaluate里fetch(url, {credentials:'include'})复用浏览器上下文 cookie,否则会回到 challenge。 - PDF 体积判断:正文通常 >1MB,
ct=='application/pdf'且len>100000才算成功,否则是 HTML challenge 页。 - 不要用 curl 硬刚:已实测 urllib 得
HTTP Error 303 ... infinite loop,POW 返回 "error code: 520"。
五、环境依赖
- Python 3.13 +
pip install playwright(无需下载 Chromium,用系统 Edge) - 系统需装 Microsoft Edge(Windows 11 自带,路径
C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe)
六、参考案例
- Ge et al. 2026 npj Digit Med(DOI 10.1038/s41746-025-02297-4):正文 10,008,319 bytes(%PDF-1.4)+ 补充 3,748,120 bytes(%PDF-1.7),一次成功。