bibtex 批量添加 doi 最容易的方法是什么?

需求: 我有几个 bib 文件,其中大多数 entries 没有 doi 字段,但现在发现这样做不规范,所有的 entries 都需要加上 doi. 几百个 entries, 手动添加比较麻烦,而且部分 entries 本来就没有 doi. 想问问据各位道友所知,批量添加 doi 最方便的方法是什么?

chatgpt 给我的几个推荐:

  • org-ref: 我没用过,调用 (org-ref-get-doi-at-point) 不成功 (我不知道这个函数应该是把 point 放在哪里调用).
  • zotero: 最大的问题是,我担心 zotero 导入再导出后,导致我的 bib 文件和之前有意料之外的不同。
  • python.

方法可以不限于 emacs.

zotero加了之后自己合并bib

还是zotero+Better BibTex插件吧。实在担心影响原始bib,那就用python把Better BibTex输出的bib里的doi提取出来,再注入自己的bib。

我用的这种做法:

import requests
import bibtexparser
import sys

def get_doi_from_title(title):
    url = f"https://api.crossref.org/works?query.title={title}&rows=1"
    try:
      response = requests.get(url, timeout=10)
      if response.status_code == 200:
          data = response.json()
          items = data.get("message", {}).get("items", [])
          if items:
              return items[0].get("DOI")
    except:
      return None

def process_bib_file(filename):
    with open(filename) as bibtex_file:
        bib_database = bibtexparser.load(bibtex_file)

    updated = False
    for entry in bib_database.entries:
        if entry.get('ENTRYTYPE') == 'misc':
            continue
        if 'doi' not in entry and 'title' in entry:
            doi = get_doi_from_title(entry['title'])
            if doi:
                entry['doi'] = doi
                updated = True
                print(f"Updated DOI for: {entry['ID']} - {entry['title']}")
            else:
                print(f"Failed to find DOI for: {entry['ID']} - {entry['title']}")

    if updated:
        with open(filename, 'w') as bibtex_file:
            bibtexparser.dump(bib_database, bibtex_file)

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: python script.py <bib_file1.bib> <bib_file2.bib> ...")
        sys.exit(1)

    for bib_file in sys.argv[1:]:
        print(f"Processing {bib_file}...")
        process_bib_file(bib_file)

这样直接:

python get-doi.py local-bib.bib

就会自动添加所有没有 doi fields 的 fields. 不需要用 zotero 之类的, 也不用任何 packages, 我觉得这个方法足够方便。