70 lines
2.8 KiB
Python
70 lines
2.8 KiB
Python
"""Free arXiv metadata provider."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import urllib.parse
|
|
import xml.etree.ElementTree as ET
|
|
from typing import Any, Dict
|
|
|
|
from .base import http_get
|
|
|
|
|
|
def resolve_arxiv_record(locator_info: Dict[str, Any]) -> Dict[str, Any]:
|
|
arxiv_id = str(locator_info.get("arxiv_id") or locator_info.get("identifier") or "").strip()
|
|
record = {
|
|
"provider_type": "arxiv",
|
|
"source_type": "paper",
|
|
"locator_type": locator_info.get("locator_type", "arxiv_id"),
|
|
"raw_locator": locator_info.get("raw_locator", ""),
|
|
"normalized_id": locator_info.get("normalized_id", f"arxiv:{arxiv_id.lower()}"),
|
|
"title": f"arXiv:{arxiv_id}" if arxiv_id else "",
|
|
"url": locator_info.get("url", ""),
|
|
"authors": [],
|
|
"year": None,
|
|
"venue": "arXiv",
|
|
"doi": "",
|
|
"arxiv_id": arxiv_id,
|
|
"parse_status": "parsed-only",
|
|
"fetch_status": "parsed-only",
|
|
"evidence_class": "parsed_locator",
|
|
"provider_metadata": {"resolved_via": "arxiv"},
|
|
}
|
|
if not arxiv_id:
|
|
return record
|
|
try:
|
|
payload = http_get(
|
|
f"https://export.arxiv.org/api/query?id_list={urllib.parse.quote(arxiv_id)}",
|
|
accept="application/atom+xml, text/xml;q=0.9",
|
|
)
|
|
root = ET.fromstring(payload.decode("utf-8", errors="ignore"))
|
|
namespace = {"atom": "http://www.w3.org/2005/Atom"}
|
|
entry = root.find("atom:entry", namespace)
|
|
if entry is None:
|
|
return {**record, "parse_status": "fetch-failed", "fetch_status": "fetch-failed"}
|
|
authors = [
|
|
(node.findtext("atom:name", default="", namespaces=namespace) or "").strip()
|
|
for node in entry.findall("atom:author", namespace)
|
|
if (node.findtext("atom:name", default="", namespaces=namespace) or "").strip()
|
|
]
|
|
published = (entry.findtext("atom:published", default="", namespaces=namespace) or "").strip()
|
|
year = int(published[:4]) if published[:4].isdigit() else None
|
|
url = record["url"]
|
|
for item in entry.findall("atom:link", namespace):
|
|
href = item.attrib.get("href", "")
|
|
if href:
|
|
url = href
|
|
break
|
|
return {
|
|
**record,
|
|
"title": (entry.findtext("atom:title", default="", namespaces=namespace) or "").strip() or record["title"],
|
|
"summary": (entry.findtext("atom:summary", default="", namespaces=namespace) or "").strip(),
|
|
"authors": authors,
|
|
"year": year,
|
|
"url": url,
|
|
"parse_status": "resolved",
|
|
"fetch_status": "network-fetched",
|
|
"evidence_class": "external_provider",
|
|
}
|
|
except Exception:
|
|
return {**record, "parse_status": "fetch-failed", "fetch_status": "fetch-failed"}
|