OAI-PMH
开放档案元数据收割协议(Open Archives Initiative Protocol for Metadata Harvesting,简称 OAI-PMH) 是图书馆、发现服务、机构知识库和学术索引机构用于收集出版物元数据的标准协议。
Academic Stack 针对已发表的期刊文章提供了 OAI-PMH 2.0 接口端点。该端点暴露 Dublin Core(都柏林核心)元数据,并支持完全收割与增量收割。
OAI-PMH 仅分发书目元数据。它不会传输文章 PDF,也不能替代 DOI 注册、Crossref 提交、站点地图或 Google Scholar 元数据。
本指南使用 https://www.publisher.com 作为出版社域名示例,使用 https://www.yourjournal.com 作为期刊域名示例。请将这些域名以及 {journal_slug} 等占位符替换为您实际部署的域名和期刊标识。
存储库接口 URL
可用的存储库接口 URL 取决于 Academic Stack 的部署类型。
企业版 / 单出版社部署
出版社级存储库包含来自所有公开期刊的文章:
https://www.publisher.com/oai
每个公开期刊也拥有独立的存储库:
https://www.publisher.com/journal/{journal_slug}/oai
例如:
https://www.publisher.com/journal/nature-science/oai
出版社级存储库使用 OAI 集(setSpec)来区分不同期刊。期刊级存储库仅包含所选期刊。
云服务 PaaS / SaaS 部署
每个期刊域名均代表一个独立的 OAI-PMH 存储库:
https://www.yourjournal.com/oai
接口仅返回属于从当前域名解析出的期刊的文章。无法通过提供期刊 ID 或 slug 来访问其他期刊。
在 PaaS / SaaS 部署模式下,不存在出版社级或全平台级的存储库。
快速验证
请在浏览器或 OAI-PMH 验证工具中打开以下 URL:
https://www.yourjournal.com/oai?verb=Identify
https://www.yourjournal.com/oai?verb=ListMetadataFormats
https://www.yourjournal.com/oai?verb=ListRecords&metadataPrefix=oai_dc
成功的响应应当为根节点是 <OAI-PMH> 的 XML,且 HTTP Content-Type 为:
Content-Type: application/xml; charset=UTF-8
支持的 OAI-PMH 请求
Academic Stack 支持全部六种 OAI-PMH 2.0 谓词(Verbs)。
| 谓词 | 用途 | 必需 / 允许参数 |
|---|---|---|
Identify | 返回存储库名称、基础 URL、管理员邮箱、时间戳策略和协议信息。 | 无 |
ListMetadataFormats | 列出存储库支持的元数据格式。 | 可选 identifier |
ListSets | 列出出版社级存储库中的期刊集。 | 无 |
ListIdentifiers | 返回记录头信息,不包含 Dublin Core 元数据。 | metadataPrefix 或 resumptionToken |
ListRecords | 返回记录头信息和 Dublin Core 元数据。 | metadataPrefix 或 resumptionToken |
GetRecord | 根据其 OAI 标识符返回一条记录。 | identifier, metadataPrefix |
接口同时支持 HTTP GET 和 POST 请求。
元数据格式
Academic Stack 当前支持:
metadataPrefix=oai_dc
oai_dc 响应使用标准的 Dublin Core 命名空间:
http://www.openarchives.org/OAI/2.0/oai_dc/
字段映射对照表
文章元数据映射如下:
| Academic Stack 字段 | Dublin Core 元素 |
|---|---|
| 文章标题 | dc:title |
| 每位作者 | dc:creator (每位作者对应一个元素) |
| 每个关键词 | dc:subject (每个关键词对应一个元素) |
| 摘要 | dc:description |
| 出版商名称 | dc:publisher |
| 出版或在线发表日期 | dc:date |
| 文章类型 | dc:type |
| DOI 链接 | dc:identifier |
| 文章详情页 URL | dc:identifier |
| 期刊、卷、期和页码 | dc:source |
| 期刊语言 | dc:language |
注:仅暴露属于公开期刊且处于公开、非删除状态的文章。
OAI 标识符
每篇文章都会分配一个稳定的 OAI 标识符:
oai:{PROJECT_NAME}:article:{article_id}
例如:
oai:academic_stack:article:345
标识符独立于:
- 期刊域名
- 期刊 slug
- DOI 变更
- 卷和期分配
- 文章详情页 URL
OAI 标识符用于标识元数据记录本身。它不是 DOI,也不是文章 URL。DOI 和详情页 URL 作为 dc:identifier 值单独提供。
请求示例:
https://www.yourjournal.com/oai?verb=GetRecord&metadataPrefix=oai_dc&identifier=oai:academic_stack:article:345
时间戳与增量收割
OAI 头部中的 <datestamp> 表示文章记录元数据的更新时间(UTC):
<datestamp>2026-07-30T08:30:00Z</datestamp>
存储库采用秒级精度:
YYYY-MM-DDThh:mm:ssZ
收割工具可以请求在特定日期范围内更新的记录:
https://www.yourjournal.com/oai?verb=ListRecords&metadataPrefix=oai_dc&from=2026-07-01T00:00:00Z
https://www.yourjournal.com/oai?verb=ListRecords&metadataPrefix=oai_dc&from=2026-07-01T00:00:00Z&until=2026-07-30T23:59:59Z
from 和 until 边界均包含在内(闭区间)。两个值都必须使用存储库的完整 UTC 时间戳格式,且 from 不能晚于 until。
元数据更新可能会使现有记录在后续的增量收割中重新出现。OAI 标识符保持不变。
分页与恢复令牌 (Resumption Token)
ListRecords 和 ListIdentifiers 每次响应最多返回 100 条记录。
当有更多记录可用时,响应中包含 resumptionToken:
<resumptionToken cursor="0">
eyJ2ZXJiIjoiTGlzdFJlY29yZHMi...
</resumptionToken>
在下一个请求中使用返回的令牌:
https://www.yourjournal.com/oai?verb=ListRecords&resumptionToken=eyJ2ZXJiIjoiTGlzdFJlY29yZHMi...
使用 resumptionToken 时:
- 仅发送
verb和resumptionToken。 - 请勿重复发送
metadataPrefix、from、until或set。 - 持续请求页面,直到不再返回
resumptionToken。 - 在一小时内使用该令牌。
令牌会保留原始请求中的存储库范围和所有筛选条件。
期刊集 (Sets)
期刊集仅在企业版 / 单出版社的出版社级存储库中可用。
列出所有期刊集:
https://www.publisher.com/oai?verb=ListSets
示例期刊集:
<set>
<setSpec>journal:nature-science</setSpec>
<setName>Nature Science</setName>
</set>
从出版社存储库收割一本期刊:
https://www.publisher.com/oai?verb=ListRecords&metadataPrefix=oai_dc&set=journal:nature-science
出版社级存储库返回的记录在其头部包含期刊集:
<header>
<identifier>oai:academic_stack:article:345</identifier>
<datestamp>2026-07-30T08:30:00Z</datestamp>
<setSpec>journal:nature-science</setSpec>
</header>
期刊级存储库不使用集。向期刊级存储库发送 ListSets 请求将返回 noSetHierarchy。
已删除记录
存储库目前声明:
<deletedRecord>no</deletedRecord>
已删除或未发表的文章不会包含在 OAI 响应中,存储库也不暴露持久的已删除记录头。
收割工具应根据 OAI-PMH 的 deletedRecord=no 策略处理此存储库。
协议错误
无效请求会返回 OAI-PMH XML 错误,而非 JSON 或 HTML 应用程序错误。
常见错误代码包括:
| 错误代码 | 含义 |
|---|---|
badVerb | 谓词缺失或不受支持。 |
badArgument | 必需参数缺失、格式错误或不允许使用。 |
cannotDisseminateFormat | 请求的元数据格式不受支持。 |
idDoesNotExist | 标识符在当前存储库中不存在。 |
noRecordsMatch | 没有记录匹配日期、集或存储库筛选条件。 |
noSetHierarchy | 期刊级存储库不支持集。 |
badResumptionToken | 令牌无效、已过期或属于另一个请求范围。 |
示例:
<error code="cannotDisseminateFormat">
Only oai_dc is supported.
</error>
推荐的收割工作流
对于首次全量收割:
- 发送
Identify。 - 发送
ListMetadataFormats。 - 如果使用出版社级存储库,发送
ListSets。 - 使用
metadataPrefix=oai_dc启动ListRecords。 - 追随每一个
resumptionToken,直到最后一页。 - 存储每条记录的 OAI 标识符和时间戳。
对于后续增量收割:
- 记录上一次成功收割的结束时间。
- 发送带有重叠
from时间戳的ListRecords,以避免遗漏边界附近的更新。 - 追随所有
resumptionToken页面。 - 按 OAI 标识符更新现有记录。
- 保存新的成功收割时间。
在计划增量收割时,在两次运行之间使用较小的重叠区间——例如,从上次成功收割时间前几分钟开始请求。OAI 标识符是稳定的,因此可以安全地按标识符更新重复结果。
常见问题排查
| 故障现象 | 建议检查 |
|---|---|
noRecordsMatch | 确认期刊和文章处于公开状态,且日期范围使用 UTC 秒级时间戳。 |
cannotDisseminateFormat | 使用 metadataPrefix=oai_dc。 |
badResumptionToken | 从原始请求重新开始收割;令牌在一小时后过期。 |
idDoesNotExist | 确认标识符属于当前期刊存储库,且文章保持公开。 |
noSetHierarchy | 仅在单出版社的出版社级 /oai 端点上使用集。 |
| 文章 URL 返回 404 | 确认文章处于公开状态,且其卷、期和文章编号有效。 |
| 元数据更改不可见 | 确认编辑后已保存文章,然后使用更新的时间戳重复增量请求。 |
在向索引服务提交 OAI-PMH 端点之前,请验证 Identify、ListRecords、分页、文章 URL、作者、日期、DOI 值和期刊元数据。