81 lines
2.6 KiB
Python
81 lines
2.6 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Search arXiv via its public Atom API. No API key required.
|
|
|
|
CLI usage:
|
|
python3 search_arxiv.py "UAV magnetic compensation" --max 10
|
|
|
|
Importable:
|
|
from search_arxiv import search_arxiv
|
|
"""
|
|
import sys
|
|
import json
|
|
import argparse
|
|
import urllib.request
|
|
import urllib.parse
|
|
import xml.etree.ElementTree as ET
|
|
|
|
ARXIV_API = "http://export.arxiv.org/api/query"
|
|
NS = {"atom": "http://www.w3.org/2005/Atom"}
|
|
|
|
|
|
def search_arxiv(query, max_results=10, timeout=20):
|
|
params = {
|
|
"search_query": f"all:{query}",
|
|
"start": 0,
|
|
"max_results": max_results,
|
|
"sortBy": "relevance",
|
|
"sortOrder": "descending",
|
|
}
|
|
url = f"{ARXIV_API}?{urllib.parse.urlencode(params)}"
|
|
with urllib.request.urlopen(url, timeout=timeout) as resp:
|
|
data = resp.read()
|
|
root = ET.fromstring(data)
|
|
results = []
|
|
for entry in root.findall("atom:entry", NS):
|
|
id_el = entry.find("atom:id", NS)
|
|
title_el = entry.find("atom:title", NS)
|
|
summary_el = entry.find("atom:summary", NS)
|
|
published_el = entry.find("atom:published", NS)
|
|
if id_el is None or title_el is None:
|
|
continue
|
|
arxiv_id_full = id_el.text.strip()
|
|
arxiv_id = arxiv_id_full.rsplit("/", 1)[-1]
|
|
title = " ".join(title_el.text.split())
|
|
summary = " ".join(summary_el.text.split()) if summary_el is not None else ""
|
|
authors = [
|
|
a.find("atom:name", NS).text
|
|
for a in entry.findall("atom:author", NS)
|
|
if a.find("atom:name", NS) is not None
|
|
]
|
|
published = published_el.text[:10] if published_el is not None else None
|
|
pdf_url = None
|
|
for link in entry.findall("atom:link", NS):
|
|
if link.attrib.get("title") == "pdf":
|
|
pdf_url = link.attrib.get("href")
|
|
results.append({
|
|
"source": "arxiv",
|
|
"arxiv_id": arxiv_id,
|
|
"title": title,
|
|
"authors": authors,
|
|
"year": published[:4] if published else None,
|
|
"published": published,
|
|
"abstract": summary,
|
|
"pdf_url": pdf_url,
|
|
"doi": 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_arxiv(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)
|