Robust Downloader(多范式论文抓取)¶
Robust Downloader(internal/downloader,builtin 插件 downloader,capability
download)解决一个问题:给一个 DOI / arXiv id / 论文 URL,把正式发表的 PDF
弄回来——不依赖单一上游,不因为一个出版社的反爬墙就放弃。
它不是替代 懒加载摄入 的 arXiv 抓取,而是把覆盖面 扩展到 arXiv 之外的正式版论文:OA 仓库、出版社模式 URL、落地页挖掘、真实浏览器、 甚至远端有校园订阅出口的代理机。抓回的 PDF 走与上传/arXiv 抓取完全相同的 存储 + 注册 + MinerU 管线。
入口有三个:
入口 |
说明 |
|---|---|
|
HTTP API(本页 + REST API) |
SPA 页面 |
粘贴一批标识符 → 提交 → 逐篇看进度与策略轨迹 |
|
CLI 现场压测(本页 CLI probe) |
前置条件:paper_access.enabled: true(复用其 fetcher/resolver/对象存储接线)+
downloader.enabled: true(默认开)。任一关闭时端点仍注册:/fetch 返回
503(detail 说明缺哪个开关),/jobs 返回空快照 200。
策略阶梯(strategy ladder)¶
每个标识符先进 registry 的 ResolveOrMint(解析或铸造 paper 记录),然后跑
策略阶梯——按序尝试,第一个通过验证的候选即胜出。每次尝试都记录在
attempt trace(策略 id、URL、错误、耗时)里,落在 job snapshot 与
paper_acquisition_events 审计表。
顺序 |
策略 id(trace 里可见) |
做什么 |
|---|---|---|
1 |
|
输入带 arXiv id 时直下 arxiv.org(最可靠、带版本) |
2 |
|
输入是 PMCID 时先经 Europe PMC 换算成真 DOI |
3 |
|
DOI-only 论文经 OpenAlex 反查 arXiv twin,回退到 |
4 |
|
OA 元数据 API 拿候选 URL。Europe PMC |
4b |
|
候选其实是绿色 OA 仓库的落地页(HAL、高校 repo…)时,先挖出真正的 PDF 链接再抓 |
5 |
|
按 DOI 前缀套出版社 URL 模板(Springer、Wiley、T&F、Sage、ACS、ACM、Frontiers、PLOS、eLife、bioRxiv 等) |
6 |
|
抓 DOI 落地页挖 |
7 |
|
前面撞上 entitlement 墙(bot/PoW challenge)时,优先于本地浏览器把整条梯子委托给 downloaderproxy(见下) |
8 |
|
经 CDP 把出版社 PDF/落地 URL 在真实 Chromium 里重放——Cloudflare/IEEE WAF 这类纯 HTTP 过不去的墙 |
9 |
|
LLM 兜底:从落地页 HTML 里提名 PDF 链接( |
10 |
|
终极兜底:以上全败(不只是 entitlement 墙)时最后委托一次代理机 |
验证管线¶
每个候选在入库前都要过同一套验证——策略只负责提名 URL,接受与否由验证决定:
%PDF-magic +%%EOFtrailer + 大小上下限;HTML 响应会被分类:
bot_challenge/pow_challenge/paywall/error_page(以及 IdP 登录跳转检测)——分类结果进 trace,是 probe 失败分类学的数据源;抓取带 cookie jar、浏览器式 headers、per-host 速率限制;
downloader.respect_robots(默认 false)可开启 robots.txt 门控。按需的 entitled fetch 不是爬虫,且不少出版社用 blanketDisallow: *反 AI 爬虫, 开启会误杀合法下载;需要严格对齐时再开。
通过的 PDF 带 provenance 入库(downloader:<strategy> + 来源 URL + sha256),
触发既有的 PDF-ready hook 驱动 MinerU 转换。
配置参考(config.yaml 的 downloader: 段)¶
完整 YAML schema 见仓库根 config.example.yaml;此处逐字段展开:
downloader:
enabled: true # 总开关;还需 paper_access.enabled: true
concurrency: 2 # 并行下载 job 数
unpaywall_email: "" # Unpaywall 联系邮箱;空则回落 paper_access.openalex_mailto
s2_api_key: "" # 可选 Semantic Scholar key(免费档,1 req/s)——
# 稳定最高召回的 OA resolver,避免共享池 429
respect_robots: false # robots.txt 门控;默认关(见上)
browser: # CDP 浏览器 lane:指向一个已在运行的 Chromium
# 的 DevTools 端点(如 ws://browser:9222)。
# 空 cdp_url = 关闭该 lane;出版社登录态就存在
# 那个浏览器 profile 里(人工登一次)
cdp_url: ""
timeout: 45s
proxy: # 委托给独立 downloaderproxy(见下)。设置后
# 优先于本地浏览器 lane
url: "" # e.g. http://ag-workstation:8602
token: "" # 与代理机的 DL_PROXY_TOKEN 同值
timeout: 5m
agent: # LLM 兜底链接提取器;backend 空 = 关
backend: "" # "" | "openai" | "claude"
base_url: "" # openai:OpenAI 兼容端点,e.g. https://llm.example.com/v1
api_key: ""
model: ""
max_tokens: 1024
claude_bin: claude # claude:本机 headless claude CLI(需已 OAuth 登录)
claude_model: "" # 空 = claude 默认模型
timeout: 120s
max_budget_usd: 0 # claude 专用;0 = 不加预算 flag
多 downloader-worker(推荐新部署)¶
主服务现在可通过 downloader.remote.enabled 管理多个主动接入的 worker。
worker 经管理员批准后领取任务、上传 PDF;主服务完成对象存储和 registry 登记后
才返回归档确认,worker 再清理暂存。支持有界并发、跨节点失败切换、断线重传与
重启恢复;仍保留本地优先策略,不需要暴露 worker 或浏览器入站端口。
详见主服务配置与迁移、worker 部署。
新模式不能与非空 downloader.proxy.url 同时启用;下节为旧协议兼容说明。
downloaderproxy:校园出口代理服务(旧协议)¶
当 qatlasd 所在网络没有出版社订阅(或被强制代理)时,把抓取委托给一台有 直连 entitlement 的机器(如校园网出口的工作站):
单容器、无 sidecar:镜像(
Dockerfile.downloaderproxy)自带一份当前版 Chrome-for-Testing(chromedp/headless-shell——出版社 WAF 会拒绝 debian 仓库里 的陈旧 chromium),entrypoint 启动它并暴露本地 CDP 端点,服务像本地浏览器 lane 一样驱动它。qatlasd 侧配
downloader.proxy.{url,token,timeout};梯子委托是 submit → poll → fetch 三步,返回的字节仍过 qatlasd 侧同一套验证管线 (策略 id 记作remote-proxy:<s>)。
# 构建与部署
docker build -f Dockerfile.downloaderproxy -t qatlas-downloaderproxy .
docker run -d --name downloader-proxy -p 8602:8602 \
-e DL_PROXY_TOKEN=<shared-secret> \
-e DL_UNPAYWALL_EMAIL=you@example.com \
-e DL_S2_API_KEY=s2k-... \
qatlas-downloaderproxy
不要给容器挂代理 env
确保容器没有 http_proxy / https_proxy(docker daemon 默认或 -e
注入),否则出口失去校园网络身份,entitlement 白挂。
服务自身的 API(设了 DL_PROXY_TOKEN 时要求 Bearer):
Method |
Path |
用途 |
|---|---|---|
|
|
|
|
|
body |
|
|
状态 + 完整 attempt trace;终态为 |
|
|
取 PDF 字节。token 单次有效,job 完成 30 分钟后过期 |
文件落在 /tmp/downloaderproxy,首次取走或过期清扫即删;重启不持久化任何状态。
浏览器 lane¶
downloader.browser.cdp_url 指向一个已经在运行的 Chromium 的 DevTools
端点(ws://…:9222)。适用场景是纯 HTTP 撞墙(Cloudflare / IEEE WAF /
PoW challenge)或 SPA 出版社站点(PDF 链接只有 JS 渲染后才出现)。需要登录态的
出版社:在那个浏览器 profile 里人工登录一次,lane 复用该会话。若部署
downloaderproxy,它自带浏览器,本地 lane 通常无需再配。
CLI probe¶
qatlasd downloader probe 是在线健壮性压测(完整 flag 表见
CLI 参考):对真实论文跑完整策略阶梯,输出
逐篇结果表 + 失败分类学汇总,任一失败 exit 1(方便脚本/CI 分支)。
不写 registry、不写对象存储——probe 的验证与 server 路径完全一致但结果只进
stdout。要求 paper_access.enabled: true。
# 指定标识符
qatlasd downloader probe 10.1038/s41586-024-07806-9 arXiv:2401.12345
# 从 OpenAlex 随机抽 30 篇有 DOI 的论文(可加检索词过滤)
qatlasd downloader probe --random 30 --search "quantum computing"
# 机读输出
qatlasd downloader probe --random 10 --json
Flag |
默认 |
含义 |
|---|---|---|
|
0 |
不给位置参数时,从 OpenAlex 抽 N 篇随机 works( |
|
— |
|
|
false |
强制启用 agent 兜底(仍需 config 里 |
|
— |
浏览器 lane CDP 端点 override(如 |
|
false |
用 config 里 |
|
— |
downloaderproxy URL override(如 |
|
— |
downloaderproxy Bearer token |
|
3 |
并行论文数 |
|
4m |
单篇阶梯预算 |
|
false |
机读 JSON 输出(替代表格) |
失败分类学(summary 里按桶计数):bot_challenge / paywall /
robots_blocked / not_pdf / 404 / 403 / rate_limited /
no_candidates / other。残余失败里 entitlement 级的终态(IEEE 202 网关、
Wiley/AIP 的 Cloudflare、非 OA 的 Nature/Elsevier 内容、HAL 的 JS 壳)正是
downloaderproxy / 浏览器 lane 要吃的范围。
管理员补救流(失败闭环)¶
抓取失败不是终点。管理员 SPA 的 acquisition failures 表
(GET /api/admin/acquisition/failures,见 REST API)列出
持久化的失败记录——阶段、原因、重试计数,附 DOI 直达链接;表格里可内联上传
人工取回的 PDF(人手动下载 → 对着 DOI 直接 POST /api/papers/{doi}/upload-pdf),
立即闭合该论文的获取状态并驱动 MinerU。已入库资产可用
Admin Asset Browser(/$lang/admin/assets)浏览 / 预览 / 下载 /
presign。