2026-07-20 03:58:38 -10:00

66 lines
2.1 KiB
Python

#!/usr/bin/env python3
"""
Search the Crossref works API. No API key required.
Good for journal articles / DOIs that arXiv and Semantic Scholar might miss.
CLI usage:
python3 search_crossref.py "UAV magnetic compensation" --max 10
Importable:
from search_crossref import search_crossref
"""
import sys
import json
import argparse
import urllib.request
import urllib.parse
CROSSREF_API = "https://api.crossref.org/works"
UA = "literature-search-verify-skill/1.0 (mailto:research-assistant@example.com)"
def search_crossref(query, max_results=10, timeout=20):
params = {"query": query, "rows": max_results}
url = f"{CROSSREF_API}?{urllib.parse.urlencode(params)}"
req = urllib.request.Request(url, headers={"User-Agent": UA})
with urllib.request.urlopen(req, timeout=timeout) as resp:
data = json.loads(resp.read())
results = []
for item in data.get("message", {}).get("items", []) or []:
titles = item.get("title") or []
title = titles[0] if titles else ""
authors = []
for a in item.get("author", []) or []:
name = " ".join(filter(None, [a.get("given"), a.get("family")]))
if name:
authors.append(name)
year = None
date_parts = (item.get("issued", {}) or {}).get("date-parts")
if date_parts and date_parts[0]:
year = date_parts[0][0]
containers = item.get("container-title") or []
results.append({
"source": "crossref",
"title": title,
"authors": authors,
"year": year,
"venue": containers[0] if containers else None,
"doi": item.get("DOI"),
"arxiv_id": None,
"abstract": None,
})
return results
if __name__ == "__main__":
ap = argparse.ArgumentParser(description=__doc__)
ap.add_argument("query")
ap.add_argument("--max", type=int, default=10)
args = ap.parse_args()
try:
out = search_crossref(args.query, args.max)
print(json.dumps(out, ensure_ascii=False, indent=2))
except Exception as e:
print(json.dumps({"error": str(e)}, ensure_ascii=False))
sys.exit(1)