Fetch paper metadata from the arxiv API.
(arxiv_id: str)
| 62 | |
| 63 | |
| 64 | def fetch_metadata(arxiv_id: str) -> dict: |
| 65 | """Fetch paper metadata from the arxiv API.""" |
| 66 | # Strip version for API query |
| 67 | base_id = re.sub(r"v\d+$", "", arxiv_id) |
| 68 | api_url = f"http://export.arxiv.org/api/query?id_list={base_id}" |
| 69 | |
| 70 | try: |
| 71 | resp = requests.get(api_url, timeout=30) |
| 72 | resp.raise_for_status() |
| 73 | except requests.RequestException as e: |
| 74 | print(f"WARNING: Could not fetch metadata from arxiv API: {e}", file=sys.stderr) |
| 75 | return {"arxiv_id": arxiv_id, "title": "Unknown", "authors": [], "abstract": "", "categories": []} |
| 76 | |
| 77 | text = resp.text |
| 78 | |
| 79 | # Simple XML parsing — avoid heavy dependencies |
| 80 | def extract_tag(tag: str, content: str) -> str: |
| 81 | pattern = rf"<{tag}[^>]*>(.*?)</{tag}>" |
| 82 | match = re.search(pattern, content, re.DOTALL) |
| 83 | return match.group(1).strip() if match else "" |
| 84 | |
| 85 | def extract_all_tags(tag: str, content: str) -> list: |
| 86 | pattern = rf"<{tag}[^>]*>(.*?)</{tag}>" |
| 87 | return [m.strip() for m in re.findall(pattern, content, re.DOTALL)] |
| 88 | |
| 89 | # Find the entry (skip the feed-level title) |
| 90 | entry_match = re.search(r"<entry>(.*?)</entry>", text, re.DOTALL) |
| 91 | if not entry_match: |
| 92 | print("WARNING: No entry found in arxiv API response.", file=sys.stderr) |
| 93 | return {"arxiv_id": arxiv_id, "title": "Unknown", "authors": [], "abstract": "", "categories": []} |
| 94 | |
| 95 | entry = entry_match.group(1) |
| 96 | |
| 97 | title = extract_tag("title", entry) |
| 98 | title = re.sub(r"\s+", " ", title) # collapse whitespace |
| 99 | |
| 100 | abstract = extract_tag("summary", entry) |
| 101 | abstract = re.sub(r"\s+", " ", abstract) |
| 102 | |
| 103 | # Authors |
| 104 | author_names = [] |
| 105 | for author_block in re.findall(r"<author>(.*?)</author>", entry, re.DOTALL): |
| 106 | name = extract_tag("name", author_block) |
| 107 | if name: |
| 108 | author_names.append(name) |
| 109 | |
| 110 | # Categories |
| 111 | categories = re.findall(r'<category[^>]*term="([^"]+)"', entry) |
| 112 | |
| 113 | return { |
| 114 | "arxiv_id": arxiv_id, |
| 115 | "title": title, |
| 116 | "authors": author_names, |
| 117 | "abstract": abstract, |
| 118 | "categories": categories, |
| 119 | } |
| 120 | |
| 121 |