如何用 Python 统计论文最近12个月的引用次数?
可以按日期窗口统计引用目标论文的不同论文数,统计对象是发表日期落在指定区间内的论文。OpenAlex 可以按日期过滤后直接读取 meta.count;Semantic Scholar 可以先在服务端过滤日期,再分页获取引用记录。原代码得到的 9000 条只是已获取的部分结果,不能作为最近12个月的最终引用数。
如果要统计的是“数据库在最近12个月新发现了多少条引用关系”,则需要历史快照或变更数据。按引用论文的发表日期过滤,无法回答这个问题。
先把日期窗口定义清楚
YEAR_START = 2025、YEAR_END = 2026 会把这两个自然年都纳入判断,无法表达精确到日的滚动窗口。
原示例中的 2025-04-25 至 2026-04-26 也略长于12个日历月。例如,以 2026-04-26 为不包含的结束日期,12个月窗口可以写为:
2025-04-26 <= publication_date < 2026-04-26
下面的 OpenAlex 示例保留问题中的两个日期,便于对照原结果;正式统计时应按选定的边界调整。
OpenAlex:先核对论文记录,再读取计数
原查询使用 referenced_works 查找引用目标论文的记录,引用方向是正确的。OpenAlex 官方文档也提供了 cites:<OpenAlex ID> 的查询方式。OpenAlex 引用查询示例
判断 51 是否异常,首先要确认 W2626778328 是否对应你想统计的论文,以及预印本、会议版本是否在该数据库中归入同一条记录。仅凭题目提供的数字,无法确认 ID 选错或存在版本拆分。
建议核对目标记录的标题、作者、DOI 和 locations 中的来源链接。不同平台的覆盖范围、参考文献提取和匹配结果也可能不同,计数不一定与 NeurIPS 页面展示的一致。OpenAlex 的引用数来自其成功匹配到目标记录的引用关系。OpenAlex 引用关系说明
如果只需要数量,可以省去下载全部结果的循环:
import os
import requests
# 沿用问题中的 ID;运行前先核对其对应的论文与版本。
OPENALEX_ID = "W2626778328"
FROM_DATE = "2025-04-25"
TO_DATE = "2026-04-26"
API_KEY = os.environ["OPENALEX_API_KEY"]
with requests.Session() as session:
response = session.get(
f"https://api.openalex.org/works/{OPENALEX_ID}",
params={"api_key": API_KEY},
timeout=30,
)
response.raise_for_status()
work = response.json()
print("ID:", work["id"])
print("Title:", work.get("display_name"))
print("DOI:", work.get("doi"))
print("Total citations:", work.get("cited_by_count"))
response = session.get(
"https://api.openalex.org/works",
params={
"api_key": API_KEY,
"filter": (
f"cites:{OPENALEX_ID},"
f"from_publication_date:{FROM_DATE},"
f"to_publication_date:{TO_DATE}"
),
"per_page": 1,
"select": "id",
},
timeout=30,
)
response.raise_for_status()
print("Citations in date range:", response.json()["meta"]["count"])
meta.count 表示匹配查询的总记录数,per_page=1 只限制响应中的明细数量。日期过滤的起止边界均包含当天。OpenAlex API 响应说明、日期过滤说明
如果这次查询的 meta.count 仍为 51,下载更多页不会增加符合该查询的记录数,应继续检查目标记录和数据覆盖。如果 meta.count 大于已下载数量,则说明明细获取不完整。
如果需要全部引用论文,可以使用 cursor=* 开始,再跟随 meta.next_cursor,避免普通分页的前 10000 条限制;当前文档支持的 per_page 上限为 100。OpenAlex 分页说明
Semantic Scholar:先过滤日期,再处理分页
原代码存在几个可以直接确认的问题:
- 只读取
year,无法判断某篇论文是否落在跨年的具体日期窗口内。 - 日志显示每次返回 1000 条,但代码配置为
limit=10000。这个配置不能保证实际返回 10000 条;当前 citations 接口文档给出的单页上限是 1000。 - 获取到 9000 条后,循环主动停止,因此后续符合条件的记录没有计入。
- 日志看起来按年份从新到旧排列,但不能据此保证后续请求始终如此;缺少排序保证时,不应因为某一页年份较早就提前结束。
当前 citations 接口支持 publicationDateOrYear,可以在服务端按日期范围过滤。下面只是单页请求示例,不能将这一页的长度作为总数:
import os
import requests
paper_id = "204e3073870fae3d05bcbc2f6a8e263d9b72e776"
response = requests.get(
f"https://api.semanticscholar.org/graph/v1/paper/{paper_id}/citations",
headers={"x-api-key": os.environ["SEMANTIC_SCHOLAR_API_KEY"]},
params={
"publicationDateOrYear": "2025-04-25:2026-04-26",
"fields": "paperId,year,publicationDate",
"offset": 0,
"limit": 1000,
},
timeout=30,
)
response.raise_for_status()
batch = response.json()
for citation in batch.get("data", []):
paper = citation.get("citingPaper") or {}
print(paper.get("paperId"), paper.get("publicationDate"))
print("Next offset:", batch.get("next"))
这里的 fields 按接口示例直接写论文属性,返回值仍位于 citingPaper 中。日期范围包含两个端点。过滤器会将缺少具体日期的论文按所属年份的 1 月 1 日处理,因此过滤结果不一定都具有真实的日级发表日期。Semantic Scholar Academic Graph API
如何处理 offset + limit must be < 10000
题目中实际返回的错误要求两者之和严格小于 10000。减小单页 limit 可以继续获取一部分记录,但无法消除整个查询的访问边界。例如,offset=9000 时,limit=999 满足不等式,limit=1000 则不满足;这不代表前一种请求已经能获取全部结果。
可以按以下步骤处理:
- 先用
publicationDateOrYear限定目标窗口,避免历史引用占用分页额度。 - 跟随响应中的
next获取后续页面,不依赖“某页年份已经较早”的提前退出判断。 - 如果过滤后的查询仍触及该边界,将日期范围拆成互不重叠的月份,再分别查询。
- 某个月仍无法完整获取时,继续拆成更小的日期区间。日期范围两端都包含,因此按月拆分时,前一区间结束于月底,后一区间应从次月 1 日开始。
- 对所有区间的结果按
citingPaper.paperId去重,并记录每个区间是否完整获取。发生错误或触及边界时,保留“结果不完整”状态。
拆分方法依赖日期过滤实际缩小查询结果。如果某一天的数据仍超过可访问范围,或服务端没有按预期对过滤后结果分页,就不能声称统计完整。此时可以考虑使用 Semantic Scholar 提供的 S2AG 数据集,在本地连接引用关系与论文日期数据后统计。Semantic Scholar Datasets API
怎样报告结果才不容易误读
报告最终结果时,应注明数据库、目标论文 ID、日期区间、查询时间和是否完整获取。引用计数应以去重后的引用论文数为单位,不能用论文中出现引用标记的次数代替。
对于缺少 publicationDate 的记录,建议单独报告数量。只有年份时,通常无法确认它是否属于跨年窗口的边界部分;按 1 月 1 日代入得到的是数据库约定下的结果,不能当成精确到日的事实。
问题中的 7537、1463 和 9000 都来自已获取记录,且没有应用日级窗口筛选。它们可以用来检查代码行为,不能据此确定这篇论文最近12个月的准确引用总数。
备注:内容仅供参考。
