PAYATHON 2026

如何用 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 则不满足;这不代表前一种请求已经能获取全部结果。

可以按以下步骤处理:

  1. 先用 publicationDateOrYear 限定目标窗口,避免历史引用占用分页额度。
  2. 跟随响应中的 next 获取后续页面,不依赖“某页年份已经较早”的提前退出判断。
  3. 如果过滤后的查询仍触及该边界,将日期范围拆成互不重叠的月份,再分别查询。
  4. 某个月仍无法完整获取时,继续拆成更小的日期区间。日期范围两端都包含,因此按月拆分时,前一区间结束于月底,后一区间应从次月 1 日开始。
  5. 对所有区间的结果按 citingPaper.paperId 去重,并记录每个区间是否完整获取。发生错误或触及边界时,保留“结果不完整”状态。

拆分方法依赖日期过滤实际缩小查询结果。如果某一天的数据仍超过可访问范围,或服务端没有按预期对过滤后结果分页,就不能声称统计完整。此时可以考虑使用 Semantic Scholar 提供的 S2AG 数据集,在本地连接引用关系与论文日期数据后统计。Semantic Scholar Datasets API

怎样报告结果才不容易误读

报告最终结果时,应注明数据库、目标论文 ID、日期区间、查询时间和是否完整获取。引用计数应以去重后的引用论文数为单位,不能用论文中出现引用标记的次数代替。

对于缺少 publicationDate 的记录,建议单独报告数量。只有年份时,通常无法确认它是否属于跨年窗口的边界部分;按 1 月 1 日代入得到的是数据库约定下的结果,不能当成精确到日的事实。

问题中的 7537、1463 和 9000 都来自已获取记录,且没有应用日级窗口筛选。它们可以用来检查代码行为,不能据此确定这篇论文最近12个月的准确引用总数。

备注:内容仅供参考。