alterlab-arxiv
Search and retrieve preprints from arXiv via the Atom API by keywords, authors, arXiv IDs, date ranges, or subject categories. Use when finding or fetching papers in physics, mathematics, computer science, quantitative biology, quantitative finance, statistics, electrical enginee
Install
npx skills add https://github.com/AlterLab-IEU/AlterLab-Academic-Skills/tree/main/skills/databases/alterlab-arxiv
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install alterlab-ieu-alterlab-academic-skills@llmmart
git clone https://github.com/AlterLab-IEU/AlterLab-Academic-Skills.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole alterlab-ieu/alterlab-academic-skills collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
arXiv Database
Overview
This skill provides Python tools for searching and retrieving preprints from arXiv.org via its public Atom API. It supports keyword search, author search, category filtering, arXiv ID lookup, and PDF download. Results are returned as structured JSON with titles, abstracts, authors, categories, and links.
The script declares its requests dependency via a PEP 723 inline header, so the most reliable way to run it is uv run scripts/arxiv_search.py ... (resolves deps automatically). The python scripts/arxiv_search.py ... examples below work when requests is already installed.
When to Use This Skill
Use this skill when:
- Searching for preprints in CS, ML, AI, physics, math, statistics, q-bio, q-fin, or economics
- Looking up specific papers by arXiv ID (e.g.,
2309.10668) - Tracking an author's recent preprints
- Filtering papers by arXiv category (e.g.,
cs.LG,cs.CL,stat.ML) - Downloading PDFs for full-text analysis
- Building literature review datasets for AI/ML research
- Monitoring new submissions in a subfield
Does NOT Trigger
| Scenario | Use Instead |
|---|---|
| Peer-reviewed, MeSH-indexed biomedical journal articles | alterlab-pubmed |
| Life-science preprints (bioRxiv / medRxiv) | alterlab-biorxiv |
| Citation counts, citation trajectories, or tracking an institution's / lab's output | alterlab-openalex |
| Depositing your own preprint on arXiv (categories, license, versioning) | alterlab-preprint-deposition |
| Multi-database systematic review with PRISMA screening | alterlab-literature-review |
Core Search Capabilities
1. Keyword Search
Search for papers by keywords in titles, abstracts, or all fields.
python scripts/arxiv_search.py \
--keywords "sparse autoencoders" "mechanistic interpretability" \
--max-results 20 \
--output results.json
With category filter:
python scripts/arxiv_search.py \
--keywords "transformer" "attention mechanism" \
--category cs.LG \
--max-results 50 \
--output transformer_papers.json
Search specific fields:
# Title only
python scripts/arxiv_search.py \
--keywords "GRPO" \
--search-field ti \
--max-results 10
# Abstract only
python scripts/arxiv_search.py \
--keywords "reward model" "RLHF" \
--search-field abs \
--max-results 30
2. Author Search
au: matches author names only — the API cannot filter by affiliation, so
au:anthropic or au:deepmind return nothing (or only papers where an organization
is listed as a collective author). To follow a lab, query its members by name; to
follow a whole institution, use alterlab-openalex (institution filter).
python scripts/arxiv_search.py \
--author "Yoshua Bengio" \
--max-results 50 \
--output bengio_papers.json
python scripts/arxiv_search.py \
--author "Ilya Sutskever" \
--category cs.LG \
--max-results 20
3. arXiv ID Lookup
Retrieve metadata for specific papers:
python scripts/arxiv_search.py \
--ids 2309.10668 2406.04093 2310.01405 \
--output sae_papers.json
Full arXiv URLs also accepted:
python scripts/arxiv_search.py \
--ids "https://arxiv.org/abs/2309.10668"
4. Category Browsing
List recent papers in a category:
python scripts/arxiv_search.py \
--category cs.AI \
--max-results 100 \
--sort-by submittedDate \
--output recent_cs_ai.json
5. PDF Download
python scripts/arxiv_search.py \
--ids 2309.10668 \
--download-pdf papers/
Batch download from search results:
import json
from scripts.arxiv_search import ArxivSearcher
searcher = ArxivSearcher()
# Search first
results = searcher.search(query="ti:sparse autoencoder", max_results=5)
# Download all
for paper in results:
arxiv_id = paper["arxiv_id"]
searcher.download_pdf(arxiv_id, f"papers/{arxiv_id.replace('/', '_')}.pdf")
arXiv Categories
Computer Science (cs.*)
| Category | Description |
|---|---|
cs.AI |
Artificial Intelligence |
cs.CL |
Computation and Language (NLP) |
cs.CV |
Computer Vision |
cs.LG |
Machine Learning |
cs.NE |
Neural and Evolutionary Computing |
cs.RO |
Robotics |
cs.CR |
Cryptography and Security |
cs.DS |
Data Structures and Algorithms |
cs.IR |
Information Retrieval |
cs.SE |
Software Engineering |
Statistics & Math
| Category | Description |
|---|---|
stat.ML |
Machine Learning (Statistics) |
stat.ME |
Methodology |
math.OC |
Optimization and Control |
math.ST |
Statistics Theory |
Other Relevant Categories
| Category | Description |
|---|---|
q-bio.BM |
Biomolecules |
q-bio.GN |
Genomics |
q-bio.QM |
Quantitative Methods |
q-fin.ST |
Statistical Finance |
eess.SP |
Signal Processing |
physics.comp-ph |
Computational Physics |
Full list: see references/api_reference.md.
Query Syntax
The arXiv API uses prefix-based field searches combined with Boolean operators.
Field prefixes:
ti:- Titleau:- Authorabs:- Abstractcat:- Categoryall:- All fields (default)co:- Commentjr:- Journal referenceid:- arXiv ID
Boolean operators (must be UPPERCASE):
ti:transformer AND abs:attention
au:bengio OR au:lecun
cat:cs.LG ANDNOT cat:cs.CV
Grouping with parentheses:
(ti:sparse AND ti:autoencoder) AND cat:cs.LG
au:"Chris Olah" AND (abs:interpretability OR abs:alignment)
Date ranges (GMT, YYYYMMDDTTTT, inclusive):
cat:cs.LG AND submittedDate:[202501010000 TO 202501312359]
Validation (since the Nov 2025 backend migration): malformed queries — unbalanced
parentheses, empty prefixes like au:, nested field syntax — return HTTP 400 with an
Atom error entry (<summary>Invalid query string: …</summary>) instead of an empty 200.
Bare terms are auto-prefixed (pineapple → all:pineapple); add raw=1 to disable
that rewriting. The script surfaces these errors instead of reporting zero results.
Examples:
from scripts.arxiv_search import ArxivSearcher
searcher = ArxivSearcher()
# Papers about SAEs in ML
results = searcher.search(
query="ti:sparse autoencoder AND cat:cs.LG",
max_results=50,
sort_by="submittedDate"
)
# Specific author in specific field
results = searcher.search(
query='au:"Neel Nanda" AND cat:cs.LG',
max_results=20
)
# Complex boolean query
results = searcher.search(
query="(abs:RLHF OR abs:reinforcement learning from human feedback) AND cat:cs.CL",
max_results=100
)
Output Format
All searches return structured JSON:
{
"query": "id_list:2309.10668",
"result_count": 1,
"results": [
{
"arxiv_id": "2309.10668",
"title": "Language Modeling Is Compression",
"authors": ["Grégoire Delétang", "Anian Ruoss", "..."],
"abstract": "Full abstract text...",
"categories": ["cs.LG", "cs.AI", "cs.CL", "cs.IT"],
"primary_category": "cs.LG",
"published": "2023-09-19T14:50:38Z",
"updated": "2024-03-18T23:15:47Z",
"doi": "",
"pdf_url": "https://arxiv.org/pdf/2309.10668v2",
"abs_url": "https://arxiv.org/abs/2309.10668v2",
"comment": "",
"journal_ref": ""
}
]
}
Common Usage Patterns
Literature Review Workflow
from scripts.arxiv_search import ArxivSearcher
import json
searcher = ArxivSearcher()
# 1. Broad search
results = searcher.search(
query="abs:mechanistic interpretability AND cat:cs.LG",
max_results=200,
sort_by="submittedDate"
)
# 2. Save results
with open("interp_papers.json", "w") as f:
json.dump({"result_count": len(results), "results": results}, f, indent=2)
# 3. Filter and analyze
import pandas as pd
df = pd.DataFrame(results)
print(f"Total papers: {len(df)}")
print(f"Date range: {df['published'].min()} to {df['published'].max()}")
print(f"\nTop categories:")
print(df["primary_category"].value_counts().head(10))
Track a Research Group
arXiv has no affiliation search, so track a group through its members' names (or
switch to alterlab-openalex and filter works by institution ID):
searcher = ArxivSearcher()
members = ["Chris Olah", "Neel Nanda", "Tom Henighan"] # the group's authors
query = "(" + " OR ".join(f'au:"{m}"' for m in members) + ") AND (cat:cs.LG OR cat:cs.CL)"
results = searcher.search(query=query, max_results=50, sort_by="submittedDate")
print(f"{len(results)} recent papers")
Monitor New Submissions
searcher = ArxivSearcher()
# Most recent ML papers
results = searcher.search(
query="cat:cs.LG",
max_results=50,
sort_by="submittedDate",
sort_order="descending"
)
for paper in results[:10]:
print(f"[{paper['published'][:10]}] {paper['title']}")
print(f" {paper['abs_url']}\n")
Python API
from scripts.arxiv_search import ArxivSearcher
searcher = ArxivSearcher(verbose=True)
# Free-form query (uses arXiv query syntax)
results = searcher.search(query="...", max_results=50)
# Lookup by ID
papers = searcher.get_by_ids(["2309.10668", "2406.04093"])
# Download PDF
searcher.download_pdf("2309.10668", "paper.pdf")
# Build query from components
query = ArxivSearcher.build_query(
title="sparse autoencoder",
author="anthropic",
category="cs.LG"
)
results = searcher.search(query=query, max_results=20)
Best Practices
- Respect rate limits: The API requests 3-second delays between calls. The script handles this automatically.
- Use category filters: Dramatically reduces noise.
cs.LGis where most ML papers live. - Cache results: Save to JSON to avoid re-fetching.
- Use
sort_by=submittedDatefor recent papers,relevancefor keyword searches. - Max 2000 results per call: arXiv caps a single request at 2000 (the script clamps to this). For larger sets, paginate with the
startparameter, up to a 30000 total cap. - arXiv IDs: Use bare IDs (
2309.10668), not full URLs, in programmatic code. - Combine with
alterlab-openalex: For citation counts and impact metrics arXiv doesn't provide.
Limitations
- No full-text search: Only searches metadata (title, abstract, authors, comments)
- No citation data: Use
alterlab-openalexor Semantic Scholar for citations - No affiliation search:
au:matches author names only - Max 2000 results per call: Use pagination (
start) for larger sets, up to a 30000 total cap. - Rate limited: ~1 request per 3 seconds recommended
- Atom XML responses: The script parses these into JSON automatically
- Search lag: New papers may take hours to appear in API results
- Strict query validation: invalid syntax returns HTTP 400 with an error entry (see Query Syntax)
Reference Documentation
- API Reference: See references/api_reference.md for full endpoint specs, all categories, and response schemas
Files (alterlab-academic-skills)
-
evals
-
evals.json 3.8 KB
{ "skill": "alterlab-arxiv", "evals": [ { "id": "keyword-category-search", "prompt": "Find me recent preprints on sparse autoencoders and mechanistic interpretability in machine learning — I want the latest stuff in cs.LG, maybe the 20 newest.", "expected_output": "Triggers the arXiv skill. Runs a keyword search (e.g. arxiv_search.py with --keywords 'sparse autoencoders' 'mechanistic interpretability') constrained to the cs.LG category, sorted by submittedDate, returning structured JSON with titles, abstracts, authors, categories, and links. Does not claim citation counts (arXiv has none).", "assertions": [ { "type": "should_trigger", "value": true }, { "type": "output_contains", "value": "cs.LG" }, { "type": "behavior", "value": "Performs a keyword search filtered by arXiv category sorted by submission date." } ] }, { "id": "arxiv-id-lookup", "prompt": "Pull the metadata and PDF link for arXiv 2309.10668 and 2406.04093 so I can add them to my reading list.", "expected_output": "Triggers the arXiv skill. Resolves the bare arXiv IDs via ID lookup (--ids / get_by_ids), returning title, authors, abstract, categories, published/updated dates, DOI, and pdf_url for each. Treats the values as arXiv identifiers, not search keywords.", "assertions": [ { "type": "should_trigger", "value": true }, { "type": "output_contains", "value": "2309.10668" }, { "type": "behavior", "value": "Resolves specific arXiv IDs to their metadata and PDF links rather than running a free-text search." } ] }, { "id": "author-tracking", "prompt": "Track the recent cs.LG preprints coming out of Anthropic — I want to monitor what their interpretability team is posting.", "expected_output": "Triggers the arXiv skill. Explains that the arXiv API's au: prefix matches author names only (au:anthropic returns nothing; affiliations are not searchable), so it builds an au:\"...\" OR query over the team's known author names, combined with cat:cs.LG and abstract terms like interpretability, sorted by submittedDate descending, and returns the recent preprint list. Uses arXiv query syntax with uppercase boolean operators and may point to alterlab-openalex for institution-level tracking.", "assertions": [ { "type": "should_trigger", "value": true }, { "type": "behavior", "value": "Constructs an author-name arXiv query (au: prefix) for the group's members rather than an affiliation search, and flags that arXiv cannot filter by affiliation." } ] }, { "id": "near-miss-pubmed", "prompt": "I need peer-reviewed clinical journal articles on metformin and cardiovascular outcomes — indexed, with MeSH terms.", "expected_output": "Should NOT trigger the arXiv skill. This is biomedical, peer-reviewed, MeSH-indexed literature, which arXiv does not cover (arXiv is preprints in physics/math/CS/quant-bio). The skill should defer to the pubmed database skill (alterlab-pubmed) for indexed clinical journal articles.", "assertions": [ { "type": "should_not_trigger", "value": true }, { "type": "output_contains", "value": "pubmed" } ] }, { "id": "near-miss-openalex", "prompt": "For the 'Attention Is All You Need' transformer paper, how many times has it been cited and what's its citation trajectory over the years?", "expected_output": "Should NOT trigger the arXiv skill. arXiv provides no citation counts or impact metrics. The request for citation counts and a citation trajectory should defer to the openalex database skill (alterlab-openalex), which exposes citation and impact data.", "assertions": [ { "type": "should_not_trigger", "value": true }, { "type": "output_contains", "value": "openalex" } ] } ] }
-
-
references
-
api_reference.md 14.1 KB
# arXiv API Reference ## Overview The arXiv API provides programmatic access to preprint metadata via an Atom XML feed. It supports search queries with field-specific operators, boolean logic, ID-based retrieval, sorting, and pagination. No authentication required. ## Base URL ``` https://export.arxiv.org/api/query ``` (The docs historically show `http://`; the endpoint also serves HTTPS, which the script uses.) **Backend migration (2025-11-11).** arXiv moved this API to a new cloud implementation with the same URL and parameters. Visible differences: malformed queries now return **HTTP 400** with an Atom error entry instead of an empty 200; bare terms are auto-prefixed (`pineapple` → `all:pineapple`) unless you pass `raw=1`; abstracts are no longer hard-wrapped at 80 characters. ## Rate Limiting - Terms of use: **no more than one request every three seconds, one connection at a time**, counted across all machines you control (https://info.arxiv.org/help/api/tou.html) - Aggressive crawling will result in temporary IP bans - Use `time.sleep(3)` between requests - Include a descriptive `User-Agent` header ## Query Parameters | Parameter | Description | Default | |-----------|-------------|---------| | `search_query` | Query string with field prefixes and boolean operators | (none) | | `id_list` | Comma-separated arXiv IDs | (none) | | `start` | Starting index for pagination (0-based) | `0` | | `max_results` | Number of results to return (max 2000 per call) | `10` | | `sortBy` | Sort field: `relevance`, `lastUpdatedDate`, `submittedDate` | `relevance` | | `sortOrder` | Sort direction: `ascending`, `descending` | `descending` | **Note**: `search_query` and `id_list` can be used together (results are ANDed) or separately. ## Search Query Syntax ### Field Prefixes | Prefix | Field | Example | |--------|-------|---------| | `ti:` | Title | `ti:transformer` | | `au:` | Author name (not affiliation) | `au:bengio` | | `abs:` | Abstract | `abs:attention mechanism` | | `co:` | Comment | `co:accepted at NeurIPS` | | `jr:` | Journal Reference | `jr:Nature` | | `cat:` | Category | `cat:cs.LG` | | `all:` | All fields | `all:deep learning` | | `id:` | arXiv ID | `id:2309.10668` | ### Boolean Operators Operators **must** be uppercase: ``` ti:transformer AND abs:attention # Both conditions au:bengio OR au:lecun # Either condition cat:cs.LG ANDNOT cat:cs.CV # Exclude category ``` ### Grouping Use parentheses for complex queries: ``` (ti:sparse AND ti:autoencoder) AND cat:cs.LG au:"Chris Olah" AND (abs:interpretability OR abs:alignment) (cat:cs.LG OR cat:cs.CL) AND ti:reinforcement learning ``` ### Phrase Search Quotes for exact phrases: ``` ti:"sparse autoencoder" au:"Yoshua Bengio" abs:"reinforcement learning from human feedback" ``` ### Date ranges `submittedDate` (and `lastUpdatedDate`) accept an inclusive range in GMT, `[YYYYMMDDTTTT TO YYYYMMDDTTTT]`: ``` cat:cs.LG AND submittedDate:[202501010000 TO 202501312359] ``` ### Affiliations There is no affiliation field to search. `au:anthropic` returns nothing; `au:openai` only matches papers that list the organization as a collective author. Query a group through its members' names, or use OpenAlex's institution filter. ### Wildcards Not supported by the arXiv API. Use broader terms and filter client-side. ## Example Requests ### Basic keyword search ``` GET http://export.arxiv.org/api/query?search_query=all:sparse+autoencoder&max_results=10 ``` ### Author + category ``` GET http://export.arxiv.org/api/query?search_query=au:bengio+AND+cat:cs.LG&max_results=50&sortBy=submittedDate ``` ### ID lookup ``` GET http://export.arxiv.org/api/query?id_list=2309.10668,2406.04093 ``` ### Combined search + ID ``` GET http://export.arxiv.org/api/query?search_query=cat:cs.LG&id_list=2309.10668 ``` ### Paginated results ``` # Page 1 (results 0-99) GET ...?search_query=cat:cs.LG&start=0&max_results=100&sortBy=submittedDate # Page 2 (results 100-199) GET ...?search_query=cat:cs.LG&start=100&max_results=100&sortBy=submittedDate ``` ## Response Format (Atom XML) The API returns an Atom 1.0 XML feed. ### Feed-level elements ```xml <?xml version="1.0" encoding="UTF-8"?> <feed xmlns="http://www.w3.org/2005/Atom" xmlns:arxiv="http://arxiv.org/schemas/atom"> <title>ArXiv Query: ...</title> <id>http://arxiv.org/api/...</id> <updated>2024-01-15T00:00:00-05:00</updated> <!-- Total results available (not just returned) --> <opensearch:totalResults>1500</opensearch:totalResults> <opensearch:startIndex>0</opensearch:startIndex> <opensearch:itemsPerPage>50</opensearch:itemsPerPage> <entry>...</entry> <entry>...</entry> </feed> ``` ### Entry elements ```xml <!-- Illustrative entry: structure only; values are placeholders. --> <entry> <!-- Unique identifier (includes version) --> <id>http://arxiv.org/abs/YYMM.NNNNNv2</id> <!-- Dates --> <published>2023-09-19T17:58:00Z</published> <updated>2023-10-04T14:22:00Z</updated> <!-- Metadata --> <title>Example Paper Title...</title> <summary>Full abstract text...</summary> <!-- Authors --> <author> <name>First Author</name> </author> <author> <name>Second Author</name> </author> <!-- Categories --> <arxiv:primary_category term="cs.LG" scheme="http://arxiv.org/schemas/atom"/> <category term="cs.LG" scheme="http://arxiv.org/schemas/atom"/> <category term="cs.AI" scheme="http://arxiv.org/schemas/atom"/> <!-- Links --> <link href="http://arxiv.org/abs/YYMM.NNNNNv2" rel="alternate" type="text/html"/> <link href="http://arxiv.org/pdf/YYMM.NNNNNv2" rel="related" type="application/pdf" title="pdf"/> <!-- Optional (present only when the author/arXiv supplies them) --> <arxiv:comment>42 pages, 30 figures</arxiv:comment> <arxiv:doi>10.1103/PhysRevLett.XX.XXXXXX</arxiv:doi> <arxiv:journal_ref>...</arxiv:journal_ref> </entry> ``` ### Entry field descriptions | Field | Description | |-------|-------------| | `id` | Canonical arXiv URL with version (e.g., `http://arxiv.org/abs/2309.10668v2`) | | `published` | First submission date (ISO 8601) | | `updated` | Last update date (ISO 8601) | | `title` | Paper title (may contain line breaks in XML) | | `summary` | Full abstract text | | `author/name` | Author full name (one per `<author>` element) | | `arxiv:primary_category` | Primary arXiv category | | `category` | All categories (multiple elements) | | `link[@type='text/html']` | Abstract page URL | | `link[@title='pdf']` | PDF download URL | | `arxiv:comment` | Author comment (page count, conference, etc.) | | `arxiv:doi` | Associated DOI (if exists) | | `arxiv:journal_ref` | Journal publication reference (if published) | ## Complete Category List ### Computer Science (cs.*) | Category | Name | |----------|------| | `cs.AI` | Artificial Intelligence | | `cs.AR` | Hardware Architecture | | `cs.CC` | Computational Complexity | | `cs.CE` | Computational Engineering, Finance, and Science | | `cs.CG` | Computational Geometry | | `cs.CL` | Computation and Language | | `cs.CR` | Cryptography and Security | | `cs.CV` | Computer Vision and Pattern Recognition | | `cs.CY` | Computers and Society | | `cs.DB` | Databases | | `cs.DC` | Distributed, Parallel, and Cluster Computing | | `cs.DL` | Digital Libraries | | `cs.DM` | Discrete Mathematics | | `cs.DS` | Data Structures and Algorithms | | `cs.ET` | Emerging Technologies | | `cs.FL` | Formal Languages and Automata Theory | | `cs.GL` | General Literature | | `cs.GR` | Graphics | | `cs.GT` | Computer Science and Game Theory | | `cs.HC` | Human-Computer Interaction | | `cs.IR` | Information Retrieval | | `cs.IT` | Information Theory | | `cs.LG` | Machine Learning | | `cs.LO` | Logic in Computer Science | | `cs.MA` | Multiagent Systems | | `cs.MM` | Multimedia | | `cs.MS` | Mathematical Software | | `cs.NA` | Numerical Analysis | | `cs.NE` | Neural and Evolutionary Computing | | `cs.NI` | Networking and Internet Architecture | | `cs.OH` | Other Computer Science | | `cs.OS` | Operating Systems | | `cs.PF` | Performance | | `cs.PL` | Programming Languages | | `cs.RO` | Robotics | | `cs.SC` | Symbolic Computation | | `cs.SD` | Sound | | `cs.SE` | Software Engineering | | `cs.SI` | Social and Information Networks | | `cs.SY` | Systems and Control | ### Statistics (stat.*) | Category | Name | |----------|------| | `stat.AP` | Applications | | `stat.CO` | Computation | | `stat.ME` | Methodology | | `stat.ML` | Machine Learning | | `stat.OT` | Other Statistics | | `stat.TH` | Statistics Theory | ### Mathematics (math.*) | Category | Name | |----------|------| | `math.AC` | Commutative Algebra | | `math.AG` | Algebraic Geometry | | `math.AP` | Analysis of PDEs | | `math.AT` | Algebraic Topology | | `math.CA` | Classical Analysis and ODEs | | `math.CO` | Combinatorics | | `math.CT` | Category Theory | | `math.CV` | Complex Variables | | `math.DG` | Differential Geometry | | `math.DS` | Dynamical Systems | | `math.FA` | Functional Analysis | | `math.GM` | General Mathematics | | `math.GN` | General Topology | | `math.GR` | Group Theory | | `math.GT` | Geometric Topology | | `math.HO` | History and Overview | | `math.IT` | Information Theory | | `math.KT` | K-Theory and Homology | | `math.LO` | Logic | | `math.MG` | Metric Geometry | | `math.MP` | Mathematical Physics | | `math.NA` | Numerical Analysis | | `math.NT` | Number Theory | | `math.OA` | Operator Algebras | | `math.OC` | Optimization and Control | | `math.PR` | Probability | | `math.QA` | Quantum Algebra | | `math.RA` | Rings and Algebras | | `math.RT` | Representation Theory | | `math.SG` | Symplectic Geometry | | `math.SP` | Spectral Theory | | `math.ST` | Statistics Theory | ### Physics | Category | Name | |----------|------| | `astro-ph` | Astrophysics (+ subcategories: .CO, .EP, .GA, .HE, .IM, .SR) | | `cond-mat` | Condensed Matter (+ subcategories) | | `gr-qc` | General Relativity and Quantum Cosmology | | `hep-ex` | High Energy Physics - Experiment | | `hep-lat` | High Energy Physics - Lattice | | `hep-ph` | High Energy Physics - Phenomenology | | `hep-th` | High Energy Physics - Theory | | `math-ph` | Mathematical Physics | | `nlin` | Nonlinear Sciences (+ subcategories) | | `nucl-ex` | Nuclear Experiment | | `nucl-th` | Nuclear Theory | | `physics` | Physics (+ subcategories: .comp-ph, .data-an, .bio-ph, etc.) | | `quant-ph` | Quantum Physics | ### Quantitative Biology (q-bio.*) | Category | Name | |----------|------| | `q-bio.BM` | Biomolecules | | `q-bio.CB` | Cell Behavior | | `q-bio.GN` | Genomics | | `q-bio.MN` | Molecular Networks | | `q-bio.NC` | Neurons and Cognition | | `q-bio.OT` | Other Quantitative Biology | | `q-bio.PE` | Populations and Evolution | | `q-bio.QM` | Quantitative Methods | | `q-bio.SC` | Subcellular Processes | | `q-bio.TO` | Tissues and Organs | ### Quantitative Finance (q-fin.*) | Category | Name | |----------|------| | `q-fin.CP` | Computational Finance | | `q-fin.EC` | Economics | | `q-fin.GN` | General Finance | | `q-fin.MF` | Mathematical Finance | | `q-fin.PM` | Portfolio Management | | `q-fin.PR` | Pricing of Securities | | `q-fin.RM` | Risk Management | | `q-fin.ST` | Statistical Finance | | `q-fin.TR` | Trading and Market Microstructure | ### Electrical Engineering and Systems Science (eess.*) | Category | Name | |----------|------| | `eess.AS` | Audio and Speech Processing | | `eess.IV` | Image and Video Processing | | `eess.SP` | Signal Processing | | `eess.SY` | Systems and Control | ### Economics (econ.*) | Category | Name | |----------|------| | `econ.EM` | Econometrics | | `econ.GN` | General Economics | | `econ.TH` | Theoretical Economics | ## Pagination The API returns at most 2000 results per request, and at most 30000 results in total across paginated calls (requests beyond that return HTTP 400). For larger result sets, paginate in slices of <=2000: ```python all_results = [] start = 0 batch_size = 100 while True: params = { "search_query": "cat:cs.LG", "start": start, "max_results": batch_size, "sortBy": "submittedDate", "sortOrder": "descending", } results = fetch(params) # your fetch function if not results: break all_results.extend(results) start += batch_size time.sleep(3) # respect rate limit ``` The total number of results available is in the `opensearch:totalResults` element of the feed. ## Downloading Papers ### PDF ``` http://arxiv.org/pdf/{arxiv_id} http://arxiv.org/pdf/{arxiv_id}v{version} ``` ### Abstract page ``` http://arxiv.org/abs/{arxiv_id} ``` ### Source (LaTeX) ``` http://arxiv.org/e-print/{arxiv_id} ``` ### HTML (experimental) ``` http://arxiv.org/html/{arxiv_id} ``` ## arXiv ID Formats | Format | Era | Example | |--------|-----|---------| | `YYMM.NNNNN` | 2015+ | `2309.10668` | | `YYMM.NNNN` | 2007-2014 | `0706.0001` | | `archive/YYMMNNN` | Pre-2007 | `hep-th/9901001` | All formats are accepted by the API. ## Common Pitfalls 1. **Boolean operators must be UPPERCASE**: `AND`, `OR`, `ANDNOT` (lowercase is treated as search terms) 2. **URL encoding**: Spaces in queries must be encoded as `+` or `%20` 3. **No full-text search**: The API only searches metadata (title, abstract, authors, etc.) 4. **Errors vs. empty results**: zero hits return a feed with `opensearch:totalResults` = 0 and no entries. Invalid queries or IDs return HTTP 400 with a single entry whose id starts with `https://arxiv.org/api/errors` and whose `<summary>` explains the problem (e.g. `Invalid query string: '(ti:sparse'`) — report it, don't treat it as "no papers" 5. **Version numbering**: `published` date is v1 submission; `updated` is latest version date 6. **Rate limiting**: Exceeding limits can result in 403 errors or temporary bans 7. **Max 2000 per request**: `max_results` is capped at 2000 per call; retrieve more via `start`-based pagination (30000 total cap) ## External Resources - arXiv API documentation: https://info.arxiv.org/help/api/index.html - arXiv API user manual: https://info.arxiv.org/help/api/user-manual.html - arXiv bulk data access: https://info.arxiv.org/help/bulk_data.html - arXiv category taxonomy: https://arxiv.org/category_taxonomy - OAI-PMH interface (for bulk metadata): https://oaipmh.arxiv.org/oai (the old `export.arxiv.org/oai2` URL now 301-redirects here) - API change announcements: https://groups.google.com/a/arxiv.org/g/api
-
-
scripts
-
arxiv_search.py 14.7 KB
#!/usr/bin/env python3 # /// script # requires-python = ">=3.9" # dependencies = ["requests>=2.31"] # /// """ arXiv Search Tool Search and retrieve preprints from arXiv via the Atom API. Supports keyword search, author search, category filtering, ID lookup, and PDF download. Run with uv (resolves the requests dependency automatically): uv run scripts/arxiv_search.py --keywords "diffusion models" --category cs.LG """ import requests import json import argparse import xml.etree.ElementTree as ET import time import sys import os import re from typing import List, Dict, Optional class ArxivSearcher: """Search interface for arXiv preprints via the Atom API.""" BASE_URL = "https://export.arxiv.org/api/query" ATOM_NS = "{http://www.w3.org/2005/Atom}" ARXIV_NS = "{http://arxiv.org/schemas/atom}" VALID_SORT_BY = ["relevance", "lastUpdatedDate", "submittedDate"] VALID_SORT_ORDER = ["ascending", "descending"] VALID_SEARCH_FIELDS = ["ti", "au", "abs", "co", "jr", "cat", "all", "id"] def __init__(self, verbose: bool = False, delay: float = 3.0): self.verbose = verbose self.delay = delay self.session = requests.Session() self.session.headers.update({ "User-Agent": "ArxivSearchTool/1.0 (scientific-skills)" }) self._last_request_time = 0.0 def _log(self, message: str): if self.verbose: print(f"[INFO] {message}", file=sys.stderr) def _rate_limit(self): """Enforce minimum delay between requests.""" elapsed = time.time() - self._last_request_time if elapsed < self.delay: wait = self.delay - elapsed self._log(f"Rate limiting: waiting {wait:.1f}s") time.sleep(wait) self._last_request_time = time.time() def _parse_entry(self, entry: ET.Element) -> Dict: """Parse a single Atom entry into a dict.""" def text(tag, ns=None): ns = ns or self.ATOM_NS el = entry.find(f"{ns}{tag}") return el.text.strip() if el is not None and el.text else "" # Authors authors = [] for author_el in entry.findall(f"{self.ATOM_NS}author"): name_el = author_el.find(f"{self.ATOM_NS}name") if name_el is not None and name_el.text: authors.append(name_el.text.strip()) # Categories categories = [] primary_category = "" for cat_el in entry.findall(f"{self.ATOM_NS}category"): term = cat_el.get("term", "") if term: categories.append(term) prim_el = entry.find(f"{self.ARXIV_NS}primary_category") if prim_el is not None: primary_category = prim_el.get("term", "") # Links pdf_url = "" abs_url = "" for link_el in entry.findall(f"{self.ATOM_NS}link"): href = link_el.get("href", "") link_type = link_el.get("type", "") link_title = link_el.get("title", "") if link_title == "pdf" or link_type == "application/pdf": pdf_url = href elif link_type == "text/html" or (not link_type and "/abs/" in href): abs_url = href # Extract arXiv ID from the Atom id field raw_id = text("id") arxiv_id = re.sub(r"^https?://arxiv\.org/abs/", "", raw_id) # Strip version suffix for the canonical ID arxiv_id_bare = re.sub(r"v\d+$", "", arxiv_id) return { "arxiv_id": arxiv_id_bare, "title": " ".join(text("title").split()), # collapse whitespace "authors": authors, "abstract": " ".join(text("summary").split()), "categories": categories, "primary_category": primary_category, "published": text("published"), "updated": text("updated"), "doi": text("doi", self.ARXIV_NS), "comment": text("comment", self.ARXIV_NS), "journal_ref": text("journal_ref", self.ARXIV_NS), "pdf_url": pdf_url, "abs_url": abs_url or f"https://arxiv.org/abs/{arxiv_id}", } def _error_summary(self, response: requests.Response) -> Optional[str]: """Return the message of an arXiv API error entry, if the feed holds one.""" try: root = ET.fromstring(response.text) except ET.ParseError: return None for entry in root.findall(f"{self.ATOM_NS}entry"): id_el = entry.find(f"{self.ATOM_NS}id") if id_el is not None and id_el.text and "/api/errors" in id_el.text: summary = entry.find(f"{self.ATOM_NS}summary") return (summary.text or "").strip() if summary is not None else id_el.text return None def _fetch(self, params: Dict) -> List[Dict]: """Execute API request and parse results. Raises ValueError when arXiv rejects the query: since the Nov 2025 backend migration, malformed queries return HTTP 400 with an Atom error entry (previously an empty 200), and that must not be reported as "0 results". """ self._rate_limit() self._log(f"Query params: {params}") response = self.session.get(self.BASE_URL, params=params, timeout=30) error = self._error_summary(response) if error: raise ValueError(f"arXiv rejected the query: {error}") response.raise_for_status() root = ET.fromstring(response.text) entries = root.findall(f"{self.ATOM_NS}entry") self._log(f"Parsed {len(entries)} entries") results = [] for entry in entries: parsed = self._parse_entry(entry) # Skip any empty placeholder entry if not parsed["title"] or parsed["arxiv_id"] == "": continue results.append(parsed) return results def search( self, query: str, max_results: int = 50, start: int = 0, sort_by: str = "relevance", sort_order: str = "descending", ) -> List[Dict]: """ Search arXiv with a query string. Args: query: arXiv query string (e.g., "ti:transformer AND cat:cs.LG") max_results: Maximum number of results (max 2000 per request; paginate with `start` for larger sets, up to 30000 total) start: Starting index for pagination sort_by: One of "relevance", "lastUpdatedDate", "submittedDate" sort_order: "ascending" or "descending" Returns: List of paper dicts """ if sort_by not in self.VALID_SORT_BY: raise ValueError(f"sort_by must be one of {self.VALID_SORT_BY}") if sort_order not in self.VALID_SORT_ORDER: raise ValueError(f"sort_order must be one of {self.VALID_SORT_ORDER}") # arXiv caps a single call at 2000 results (slices of at most 2000). max_results = min(max_results, 2000) params = { "search_query": query, "start": start, "max_results": max_results, "sortBy": sort_by, "sortOrder": sort_order, } return self._fetch(params) def get_by_ids(self, arxiv_ids: List[str]) -> List[Dict]: """ Retrieve papers by their arXiv IDs. Args: arxiv_ids: List of arXiv IDs (e.g., ["2309.10668", "2406.04093"]) Returns: List of paper dicts """ # Clean IDs: strip URLs, versions clean_ids = [] for aid in arxiv_ids: aid = re.sub(r"^https?://arxiv\.org/abs/", "", aid.strip()) aid = re.sub(r"v\d+$", "", aid) clean_ids.append(aid) params = { "id_list": ",".join(clean_ids), "max_results": len(clean_ids), } return self._fetch(params) def download_pdf(self, arxiv_id: str, output_path: str) -> bool: """ Download a paper's PDF. Args: arxiv_id: arXiv ID (e.g., "2309.10668") output_path: File path or directory to save to Returns: True if successful """ arxiv_id = re.sub(r"^https?://arxiv\.org/abs/", "", arxiv_id.strip()) arxiv_id = re.sub(r"v\d+$", "", arxiv_id) pdf_url = f"https://arxiv.org/pdf/{arxiv_id}" self._log(f"Downloading: {pdf_url}") # If output_path is a directory, generate filename if os.path.isdir(output_path): filename = arxiv_id.replace("/", "_") + ".pdf" output_path = os.path.join(output_path, filename) self._rate_limit() try: response = self.session.get(pdf_url, timeout=60) response.raise_for_status() os.makedirs(os.path.dirname(output_path) or ".", exist_ok=True) with open(output_path, "wb") as f: f.write(response.content) self._log(f"Saved to: {output_path}") return True except Exception as e: self._log(f"Download error: {e}") return False @staticmethod def build_query( title: Optional[str] = None, author: Optional[str] = None, abstract: Optional[str] = None, category: Optional[str] = None, all_fields: Optional[str] = None, ) -> str: """ Build an arXiv query string from components. Args: title: Search in title author: Search by author name abstract: Search in abstract category: Filter by category (e.g., "cs.LG") all_fields: Search all fields Returns: arXiv query string """ parts = [] if all_fields: parts.append(f"all:{all_fields}") if title: parts.append(f"ti:{title}") if author: parts.append(f"au:{author}") if abstract: parts.append(f"abs:{abstract}") if category: parts.append(f"cat:{category}") return " AND ".join(parts) def main(): parser = argparse.ArgumentParser( description="Search arXiv preprints", formatter_class=argparse.RawDescriptionHelpFormatter, epilog=""" Examples: %(prog)s --keywords "sparse autoencoder" --category cs.LG --max-results 20 %(prog)s --author "Yoshua Bengio" --max-results 50 %(prog)s --ids 2309.10668 2406.04093 %(prog)s --query "ti:GRPO AND cat:cs.LG" --sort-by submittedDate %(prog)s --ids 2309.10668 --download-pdf papers/ """, ) parser.add_argument("--verbose", "-v", action="store_true") search_group = parser.add_argument_group("Search options") search_group.add_argument("--keywords", "-k", nargs="+", help="Keywords to search") search_group.add_argument("--author", "-a", help="Author name") search_group.add_argument("--ids", nargs="+", help="arXiv IDs to look up") search_group.add_argument("--query", "-q", help="Raw arXiv query string") search_group.add_argument( "--search-field", choices=ArxivSearcher.VALID_SEARCH_FIELDS, default="all", help="Field to search keywords in (default: all)", ) filter_group = parser.add_argument_group("Filter options") filter_group.add_argument("--category", "-c", help="arXiv category (e.g., cs.LG)") filter_group.add_argument("--max-results", type=int, default=50, help="Max results (default: 50, max: 2000 per call)") filter_group.add_argument( "--sort-by", choices=ArxivSearcher.VALID_SORT_BY, default=None, help="Sort field (default: relevance; submittedDate when browsing a category)", ) filter_group.add_argument( "--sort-order", choices=ArxivSearcher.VALID_SORT_ORDER, default="descending", ) output_group = parser.add_argument_group("Output options") output_group.add_argument("--output", "-o", help="Output JSON file (default: stdout)") output_group.add_argument("--download-pdf", help="Download PDFs to this directory") args = parser.parse_args() searcher = ArxivSearcher(verbose=args.verbose) # --- ID lookup --- if args.ids: if args.download_pdf: for aid in args.ids: searcher.download_pdf(aid, args.download_pdf) return 0 results = searcher.get_by_ids(args.ids) query_desc = f"id_list:{','.join(args.ids)}" # --- Raw query --- elif args.query: query = args.query if args.category and f"cat:{args.category}" not in query: query = f"({query}) AND cat:{args.category}" results = searcher.search( query=query, max_results=args.max_results, sort_by=args.sort_by or "relevance", sort_order=args.sort_order, ) query_desc = query # --- Keyword search --- elif args.keywords: field = args.search_field keyword_parts = [f'{field}:"{kw}"' if " " in kw else f"{field}:{kw}" for kw in args.keywords] query = " AND ".join(keyword_parts) if args.category: query = f"({query}) AND cat:{args.category}" results = searcher.search( query=query, max_results=args.max_results, sort_by=args.sort_by or "relevance", sort_order=args.sort_order, ) query_desc = query # --- Author search --- elif args.author: query = f'au:"{args.author}"' if args.category: query = f"{query} AND cat:{args.category}" results = searcher.search( query=query, max_results=args.max_results, sort_by=args.sort_by or "relevance", sort_order=args.sort_order, ) query_desc = query # --- Category browse --- elif args.category: query = f"cat:{args.category}" results = searcher.search( query=query, max_results=args.max_results, sort_by=args.sort_by or "submittedDate", sort_order=args.sort_order, ) query_desc = query else: parser.error("Provide --keywords, --author, --ids, --query, or --category") return 1 # Output output_data = { "query": query_desc, "result_count": len(results), "results": results, } output_json = json.dumps(output_data, indent=2, ensure_ascii=False) if args.output: os.makedirs(os.path.dirname(args.output) or ".", exist_ok=True) with open(args.output, "w") as f: f.write(output_json) print(f"Results written to {args.output}", file=sys.stderr) else: print(output_json) return 0 if __name__ == "__main__": try: sys.exit(main()) except (ValueError, requests.exceptions.RequestException) as e: print(f"Error: {e}", file=sys.stderr) sys.exit(2)
-
-
SKILL.md 11.5 KB
--- name: alterlab-arxiv description: Search and retrieve preprints from arXiv via the Atom API by keywords, authors, arXiv IDs, date ranges, or subject categories. Use when finding or fetching papers in physics, mathematics, computer science, quantitative biology, quantitative finance, statistics, electrical engineering, or economics, or resolving an arXiv ID to its metadata and PDF. Part of the AlterLab Academic Skills suite. license: MIT allowed-tools: Read WebFetch Bash(curl:*) Bash(python:*) Bash(uv:*) compatibility: Keyless arXiv Atom API (no authentication required) metadata: skill-author: AlterLab version: "1.1.0" last_updated: "2026-09-23" --- # arXiv Database ## Overview This skill provides Python tools for searching and retrieving preprints from arXiv.org via its public Atom API. It supports keyword search, author search, category filtering, arXiv ID lookup, and PDF download. Results are returned as structured JSON with titles, abstracts, authors, categories, and links. The script declares its `requests` dependency via a PEP 723 inline header, so the most reliable way to run it is `uv run scripts/arxiv_search.py ...` (resolves deps automatically). The `python scripts/arxiv_search.py ...` examples below work when `requests` is already installed. ## When to Use This Skill Use this skill when: - Searching for preprints in CS, ML, AI, physics, math, statistics, q-bio, q-fin, or economics - Looking up specific papers by arXiv ID (e.g., `2309.10668`) - Tracking an author's recent preprints - Filtering papers by arXiv category (e.g., `cs.LG`, `cs.CL`, `stat.ML`) - Downloading PDFs for full-text analysis - Building literature review datasets for AI/ML research - Monitoring new submissions in a subfield ### Does NOT Trigger | Scenario | Use Instead | |----------|-------------| | Peer-reviewed, MeSH-indexed biomedical journal articles | `alterlab-pubmed` | | Life-science preprints (bioRxiv / medRxiv) | `alterlab-biorxiv` | | Citation counts, citation trajectories, or tracking an institution's / lab's output | `alterlab-openalex` | | Depositing your own preprint on arXiv (categories, license, versioning) | `alterlab-preprint-deposition` | | Multi-database systematic review with PRISMA screening | `alterlab-literature-review` | ## Core Search Capabilities ### 1. Keyword Search Search for papers by keywords in titles, abstracts, or all fields. ```bash python scripts/arxiv_search.py \ --keywords "sparse autoencoders" "mechanistic interpretability" \ --max-results 20 \ --output results.json ``` With category filter: ```bash python scripts/arxiv_search.py \ --keywords "transformer" "attention mechanism" \ --category cs.LG \ --max-results 50 \ --output transformer_papers.json ``` Search specific fields: ```bash # Title only python scripts/arxiv_search.py \ --keywords "GRPO" \ --search-field ti \ --max-results 10 # Abstract only python scripts/arxiv_search.py \ --keywords "reward model" "RLHF" \ --search-field abs \ --max-results 30 ``` ### 2. Author Search `au:` matches **author names only** — the API cannot filter by affiliation, so `au:anthropic` or `au:deepmind` return nothing (or only papers where an organization is listed as a collective author). To follow a lab, query its members by name; to follow a whole institution, use `alterlab-openalex` (institution filter). ```bash python scripts/arxiv_search.py \ --author "Yoshua Bengio" \ --max-results 50 \ --output bengio_papers.json ``` ```bash python scripts/arxiv_search.py \ --author "Ilya Sutskever" \ --category cs.LG \ --max-results 20 ``` ### 3. arXiv ID Lookup Retrieve metadata for specific papers: ```bash python scripts/arxiv_search.py \ --ids 2309.10668 2406.04093 2310.01405 \ --output sae_papers.json ``` Full arXiv URLs also accepted: ```bash python scripts/arxiv_search.py \ --ids "https://arxiv.org/abs/2309.10668" ``` ### 4. Category Browsing List recent papers in a category: ```bash python scripts/arxiv_search.py \ --category cs.AI \ --max-results 100 \ --sort-by submittedDate \ --output recent_cs_ai.json ``` ### 5. PDF Download ```bash python scripts/arxiv_search.py \ --ids 2309.10668 \ --download-pdf papers/ ``` Batch download from search results: ```python import json from scripts.arxiv_search import ArxivSearcher searcher = ArxivSearcher() # Search first results = searcher.search(query="ti:sparse autoencoder", max_results=5) # Download all for paper in results: arxiv_id = paper["arxiv_id"] searcher.download_pdf(arxiv_id, f"papers/{arxiv_id.replace('/', '_')}.pdf") ``` ## arXiv Categories ### Computer Science (cs.*) | Category | Description | |----------|-------------| | `cs.AI` | Artificial Intelligence | | `cs.CL` | Computation and Language (NLP) | | `cs.CV` | Computer Vision | | `cs.LG` | Machine Learning | | `cs.NE` | Neural and Evolutionary Computing | | `cs.RO` | Robotics | | `cs.CR` | Cryptography and Security | | `cs.DS` | Data Structures and Algorithms | | `cs.IR` | Information Retrieval | | `cs.SE` | Software Engineering | ### Statistics & Math | Category | Description | |----------|-------------| | `stat.ML` | Machine Learning (Statistics) | | `stat.ME` | Methodology | | `math.OC` | Optimization and Control | | `math.ST` | Statistics Theory | ### Other Relevant Categories | Category | Description | |----------|-------------| | `q-bio.BM` | Biomolecules | | `q-bio.GN` | Genomics | | `q-bio.QM` | Quantitative Methods | | `q-fin.ST` | Statistical Finance | | `eess.SP` | Signal Processing | | `physics.comp-ph` | Computational Physics | Full list: see [references/api_reference.md](references/api_reference.md). ## Query Syntax The arXiv API uses prefix-based field searches combined with Boolean operators. **Field prefixes:** - `ti:` - Title - `au:` - Author - `abs:` - Abstract - `cat:` - Category - `all:` - All fields (default) - `co:` - Comment - `jr:` - Journal reference - `id:` - arXiv ID **Boolean operators** (must be UPPERCASE): ``` ti:transformer AND abs:attention au:bengio OR au:lecun cat:cs.LG ANDNOT cat:cs.CV ``` **Grouping with parentheses:** ``` (ti:sparse AND ti:autoencoder) AND cat:cs.LG au:"Chris Olah" AND (abs:interpretability OR abs:alignment) ``` **Date ranges** (GMT, `YYYYMMDDTTTT`, inclusive): ``` cat:cs.LG AND submittedDate:[202501010000 TO 202501312359] ``` **Validation (since the Nov 2025 backend migration):** malformed queries — unbalanced parentheses, empty prefixes like `au:`, nested field syntax — return **HTTP 400** with an Atom error entry (`<summary>Invalid query string: …</summary>`) instead of an empty 200. Bare terms are auto-prefixed (`pineapple` → `all:pineapple`); add `raw=1` to disable that rewriting. The script surfaces these errors instead of reporting zero results. **Examples:** ```python from scripts.arxiv_search import ArxivSearcher searcher = ArxivSearcher() # Papers about SAEs in ML results = searcher.search( query="ti:sparse autoencoder AND cat:cs.LG", max_results=50, sort_by="submittedDate" ) # Specific author in specific field results = searcher.search( query='au:"Neel Nanda" AND cat:cs.LG', max_results=20 ) # Complex boolean query results = searcher.search( query="(abs:RLHF OR abs:reinforcement learning from human feedback) AND cat:cs.CL", max_results=100 ) ``` ## Output Format All searches return structured JSON: ```json { "query": "id_list:2309.10668", "result_count": 1, "results": [ { "arxiv_id": "2309.10668", "title": "Language Modeling Is Compression", "authors": ["Grégoire Delétang", "Anian Ruoss", "..."], "abstract": "Full abstract text...", "categories": ["cs.LG", "cs.AI", "cs.CL", "cs.IT"], "primary_category": "cs.LG", "published": "2023-09-19T14:50:38Z", "updated": "2024-03-18T23:15:47Z", "doi": "", "pdf_url": "https://arxiv.org/pdf/2309.10668v2", "abs_url": "https://arxiv.org/abs/2309.10668v2", "comment": "", "journal_ref": "" } ] } ``` ## Common Usage Patterns ### Literature Review Workflow ```python from scripts.arxiv_search import ArxivSearcher import json searcher = ArxivSearcher() # 1. Broad search results = searcher.search( query="abs:mechanistic interpretability AND cat:cs.LG", max_results=200, sort_by="submittedDate" ) # 2. Save results with open("interp_papers.json", "w") as f: json.dump({"result_count": len(results), "results": results}, f, indent=2) # 3. Filter and analyze import pandas as pd df = pd.DataFrame(results) print(f"Total papers: {len(df)}") print(f"Date range: {df['published'].min()} to {df['published'].max()}") print(f"\nTop categories:") print(df["primary_category"].value_counts().head(10)) ``` ### Track a Research Group arXiv has no affiliation search, so track a group through its members' names (or switch to `alterlab-openalex` and filter works by institution ID): ```python searcher = ArxivSearcher() members = ["Chris Olah", "Neel Nanda", "Tom Henighan"] # the group's authors query = "(" + " OR ".join(f'au:"{m}"' for m in members) + ") AND (cat:cs.LG OR cat:cs.CL)" results = searcher.search(query=query, max_results=50, sort_by="submittedDate") print(f"{len(results)} recent papers") ``` ### Monitor New Submissions ```python searcher = ArxivSearcher() # Most recent ML papers results = searcher.search( query="cat:cs.LG", max_results=50, sort_by="submittedDate", sort_order="descending" ) for paper in results[:10]: print(f"[{paper['published'][:10]}] {paper['title']}") print(f" {paper['abs_url']}\n") ``` ## Python API ```python from scripts.arxiv_search import ArxivSearcher searcher = ArxivSearcher(verbose=True) # Free-form query (uses arXiv query syntax) results = searcher.search(query="...", max_results=50) # Lookup by ID papers = searcher.get_by_ids(["2309.10668", "2406.04093"]) # Download PDF searcher.download_pdf("2309.10668", "paper.pdf") # Build query from components query = ArxivSearcher.build_query( title="sparse autoencoder", author="anthropic", category="cs.LG" ) results = searcher.search(query=query, max_results=20) ``` ## Best Practices 1. **Respect rate limits**: The API requests 3-second delays between calls. The script handles this automatically. 2. **Use category filters**: Dramatically reduces noise. `cs.LG` is where most ML papers live. 3. **Cache results**: Save to JSON to avoid re-fetching. 4. **Use `sort_by=submittedDate`** for recent papers, `relevance` for keyword searches. 5. **Max 2000 results per call**: arXiv caps a single request at 2000 (the script clamps to this). For larger sets, paginate with the `start` parameter, up to a 30000 total cap. 6. **arXiv IDs**: Use bare IDs (`2309.10668`), not full URLs, in programmatic code. 7. **Combine with `alterlab-openalex`**: For citation counts and impact metrics arXiv doesn't provide. ## Limitations - **No full-text search**: Only searches metadata (title, abstract, authors, comments) - **No citation data**: Use `alterlab-openalex` or Semantic Scholar for citations - **No affiliation search**: `au:` matches author names only - **Max 2000 results per call**: Use pagination (`start`) for larger sets, up to a 30000 total cap. - **Rate limited**: ~1 request per 3 seconds recommended - **Atom XML responses**: The script parses these into JSON automatically - **Search lag**: New papers may take hours to appear in API results - **Strict query validation**: invalid syntax returns HTTP 400 with an error entry (see Query Syntax) ## Reference Documentation - **API Reference**: See [references/api_reference.md](references/api_reference.md) for full endpoint specs, all categories, and response schemas
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.