#!/usr/bin/env python3 """ Search the Semantic Scholar Graph API. No API key required for light use; set the S2_API_KEY environment variable for higher rate limits. CLI usage: python3 search_semantic_scholar.py "UAV magnetic compensation" --max 10 Importable: from search_semantic_scholar import search_s2 """ import sys import os import json import argparse import urllib.parse sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) from http_utils import fetch S2_API = "https://api.semanticscholar.org/graph/v1/paper/search" FIELDS = "title,authors,year,venue,externalIds,abstract,citationCount" def search_s2(query, max_results=10, timeout=20): params = {"query": query, "limit": max_results, "fields": FIELDS} url = f"{S2_API}?{urllib.parse.urlencode(params)}" headers = {} api_key = os.environ.get("S2_API_KEY") if api_key: headers["x-api-key"] = api_key data = json.loads(fetch(url, headers=headers, timeout=timeout)) results = [] for p in data.get("data", []) or []: ext = p.get("externalIds") or {} results.append({ "source": "semantic_scholar", "title": p.get("title"), "authors": [a.get("name") for a in (p.get("authors") or [])], "year": p.get("year"), "venue": p.get("venue"), "doi": ext.get("DOI"), "arxiv_id": ext.get("ArXiv"), "abstract": p.get("abstract"), "citation_count": p.get("citationCount"), }) 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_s2(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)