ScanSci Sort — 大清单文献分类摸底
核心原则:先嗅探、后下载;分类一次、路由到底。4000 篇实测嗅探 ≈30 分钟,之后每层下载只处理属于自己的桶。
环境检查
工具列表有 scansci_pdf_* → 可用 MCP(嗅探主要靠自写并发脚本,MCP 非必需);否则用 CLI scansci-pdf check 确认依赖。
嗅探阶段(只查不载)
0. 数据卫生
- 去重、去空、规范化 DOI:剥
https://doi.org/前缀、小写、trim;正则^10\.\d{4,9}/.+校验。 - WOS 导出约 5–6% 行缺 DOI → 提前分离单独文件,不进主流程。
1. OA 判定(全量,不碰灰色源)
- 首选 OpenAlex:50 DOI/请求、10 并发、~3 min/4000 篇。⚠️ 免费配额按 IP 每日计,共享 IP 可能 429(
$0 remaining)。 - 二选 Semantic Scholar 批量:
POST /graph/v1/paper/batch?fields=isOpenAccess,openAccessPdf&id=DOI:...,500 篇/请求、无需邮箱、429 退避 10–20s 可续;openAccessPdf直链质量不错。5645 篇 12 批 ≈3 min(2026-09 实测)。 - 兜底 Unpaywall 单点并发:10 并发、3 次重试、每 500 条落盘 JSON 断点续传,~17 min/4000 篇。⚠️ 批量端点
POST /v2/dois经常 500,不可依赖。 - ⚠️ Unpaywall 拒绝占位邮箱(422
Please use your own email address,错误在响应 body):必须传真实用户邮箱,启动前先拿 1 条 DOI 验证;config.py的默认scansci-pdf@example.invalid不可用于 Unpaywall。插件本体(mcpscansci_pdf_download)已改为:缺/被拒邮箱时返回error_type=config_needed+action=ask_user_email(带 agent_hint),先向用户要邮箱再跑,不要静默跳过该渠道。 - 查不到的 DOI 用 Crossref
api.crossref.org/works/{doi}验证:404 = 未注册(中文刊常见),不代表 Sci-Hub 没有。
2. 灰色源嗅探(只对非 OA 子集,请求量天然减半)
- Sci-Hub 三镜像轮测:
sci-hub.vg/sci-hub.al/sci-hub.ee(国内可达性 2026-08 实测;se/ru/st/ws/wf 不通,ru 返回反爬页)。 - 15 并发、每篇 3 次重试轮换域名。四分类:hit(HTML 含
(embed|iframe) src="...pdf,命中页 ~8KB)/ miss / turnstile(含challenges.cloudflare.com/turnstile或Verification - Sci-Hub,按 IP 频率随机插入,假 DOI 也会触发)/ blocked(403/503)。 - ⚠️ HTTP 200 ≠ 成功,验证页也是 200,必须看内容。
- LibGen 活着但有两道闸(2026-09 实测,推翻旧的"全镜像不可达"记录):
libgen.li走代理/libgen.bz直连均可达;①裸请求拿到 200 空体——必须先 GET 首页拿会话 cookie 再带 Referer 请求ads.php?doi=(插件已内置);②文件 CDN(booksdl)大概率 503,对get.php链接重试 3-4 次必中。搜不到结果时先区分"没会话"和"真没有"。 - 三镜像全 miss = 灰色源确认无。
3. 合法 OA 补捞(对 Sci-Hub miss 子集)
- OpenAIRE:
api.openaire.eu/search/publications?doi={doi}&format=json,8 并发,递归提取webresource.url过滤doi.org。实测 837 篇 miss 捞回 136 条记录、5 篇确定直链。 - 链接分型:
.pdf直链→命中;PubMed 页→NCBI elink 查 PMC(多数无);Scopus/Lens→无用;机构库 landing→GET 页面找.pdf链接。 - DOAJ API:
doaj.org/api/search/articles/{doi}补期刊官网直链。 - 403/超时 ≠ 无全文(反爬/网络),标注"记录存在但连通受限"。
4. 分类落库
- 分类值:
OA-开源/Sci-Hub有/仓库有全文/需机构权限/缺DOI。 - 灰色层默认启用(
config的scihub_enabled默认true),L2 嗅探是核心流程,不要跳过。仅当用户明确要求合规模式或环境(如严格代理)确实无法访问灰色源时才跳过 L2,此时保持分类值一致:Sci-Hub有桶并入需机构权限并在报告标注,不要自造非标准桶名;环境恢复后应补跑 L2 把桶拆回来。 - 写回原 Excel 加两列(按 DOI 匹配):
获取分诊(分桶值+配色)和已下载/编号(人工主键,可选);输出 UTF-8 BOM CSV 报告;生成分桶文件oa.txt/scihub.txt/repo.txt/institution.txt。用scripts/sort_finalize_writeback.py。 - 课题组用户通常用自己的编号做主键(WOS 筛选表的
Serial No.ID):回写列填该编号、下载文件重命名加同前缀({前缀}{编号}_{doi规范化}.pdf),比裸 DOI 文件名更符合他们的工作流。
下载路由(分类完成后移交)
| 层 | 对象 | 渠道 | 速度 | 详见 skill |
|---|---|---|---|---|
| L1 | OA-开源 | Unpaywall best_oa_location.pdf_url 直链 |
<1s/篇 | — |
| L1.5 | OA-开源 MDPI | scripts/sort_mdpi_res_batch.py(mdpi-res CDN 规律直连) |
~1.5s/篇 | — |
| L2 | Sci-Hub有 | scansci-pdf batch --scihub |
竞速 10–30s/篇 | scansci-batch |
| L3 | 需机构∩DOI前缀10.1016 |
Elsevier API(key+校园网,无需 insttoken) | 1–2s/篇 | scansci-institution |
| L4 | 需机构其余 | WebVPN/CARSI | 10–30s/篇 | scansci-institution |
| — | 仓库有全文 | 报告里仓储直链 | <1s/篇 | — |
路由原则:按 DOI 前缀把 L3 插到 L4 之前(实测需机构桶 Elsevier 占 56%)。
L1.5 MDPI CDN 直连(5645 篇清单实测 268/285=94%)
www.mdpi.com/pdf 对脚本 403(Cloudflare 按 TLS 指纹拦:python-ssl 必挂,curl 走代理也挂),但 CDN mdpi-res.com 开放且 URL 可构造:
https://mdpi-res.com/d_attachment/{slug}/{slug}-{vol:02d}-{art:05d}/article_deploy/{同名}[-v2|-v3|-v4].pdf
- slug = 期刊全名,不是 DOI 前缀:
su→sustainability、atmos→atmosphere、w→water、f→forests(ijerph/toxics/molecules 等本来就是全名的例外)。 - 文件名里没有期号:DOI 数字 = 卷 + 期(2位) + 文号(4–5位);卷补零到 2、文号补零到 5(
toxics10100577→toxics-10-00577,min9030139→minerals-09-00139,卷 1 位的老刊要用vol:1再补零拆)。 - 直链 404 就换
-v2/-v3/-v4后缀;连打会触发临时 IP 封锁(SSL EOF,~10min 自愈),串行 + 0.3–0.5s 间隔,429/EOF 就冷却别硬冲。 - mdpi.com 主站(非 CDN)无论代理还是直连都可能 403 挑战页——不要依赖它,只打 mdpi-res.com。
关键坑速查
| 坑 | 处理 |
|---|---|
| OpenAlex 429 配额耗尽 | 切 Semantic Scholar 批量 → Unpaywall 单点并发 |
| Unpaywall 批量端点 500 / 占位邮箱 422 | 单点 + 并发 + 断点续传;真实用户邮箱(启动先用 1 条 DOI 验证) |
| Turnstile 混入探测 | 四分类 + 重试 + 轮换域名 |
| 本机代理 127.0.0.1:7890 可能未启动 | 探测前先测代理连通 |
| 代理开着但出口 IP 被 Cloudflare 记账 | 双路径预检:同一 URL 各测直连(curl --noproxy "*")/代理,分域名记住可用路径(实测同站"代理挂/直连通"与反之都存在) |
| mdpi-res SSL EOF 突发 | IP 被临时记账,冷却 ~10min 自愈;串行节流预防 |
| 无效 DOI(Crossref 404) | 以 Sci-Hub 探测结果为准归类 |
| 后台 Python"卡死"假象 | python -u + 日志落文件(stdout 全缓冲看不见进度) |
| Windows 批量改名 WinError 32 | 重命名步骤放在下载层全部结束后单独跑,跳过占用文件重试 |
交付物兼容性
- 打 zip 发给用户不要用
tar -a -cf x.zip(Windows 资源管理器判"无效",中央目录不完整);用python zipfile(PDF 已压缩,ZIP_STORED即可,500 文件/1.3GB 秒级)。 - CSV 报告保持 UTF-8 BOM(Excel 直开不乱码)。
- 断点续传统一
<layer>_log.jsonl约定,层内脚本重启自动跳过已完成项。
耗时基线(4000 篇实测)
嗅探全程 ~30 min(OpenAlex 可用时);L1 ~10 min;L2 1–3 h(并发);L3 ~15 min/500 篇;L4 每篇需浏览器登录态。