Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Milestone 1 - Data Crawling

This milestone builds the raw corpus: every version of every assigned arXiv paper, with its full LaTeX source (figures removed), its metadata, and the metadata of its references. All numbers below are computed from the crawl databases when the book is built.

1. Scope

The Lab Instructors assigned each member of Group 15 a range of about 5,000 arXiv IDs. A range that crosses a month boundary (m2) is split into two spans; the open span ends at the first batch of IDs for which arXiv returns no paper.

MemberNameRange
m1Nguyễn Cát Huy2610.02471 - 2610.07470
m2Tiết Trọng Khiêm2608.29007 - end of 2608, 2609.00001 - 2609.02833
m3Nguyễn Trực Phúc2607.18694 - 2607.23693
m4Lê Kiến Quốc2607.08694 - 2607.13693
m5Trịnh Tấn Phát2601.08156 - 2601.13155
Source
Loading...

2. Implementation

The crawler is a Python package (src/introds) driven by one resumable command, python -m introds crawl --member <m> [--s3]. It records the state of every paper, version and reference request in a SQLite database, so an interrupted run continues where it stopped.

assigned IDs ──► 1. discovery (arXiv API) ──► papers + versions
                                         ├──► 2a. S3 bulk archive (latest versions, optional)
                                         │    2b. export.arxiv.org (every version still missing) ──► .tex / .bib
                                         └──► 3. references (Semantic Scholar) ──► reference metadata

2.1 Entry discovery

We query the arXiv API through arxiv.py (Client.results(Search(id_list=...))) with batches of 100 IDs. The short ID of each result carries the latest version (2601.08157v3), which gives the number of versions, the v1 date (published) and the date of the latest version (updated). IDs missing from the response are stored as not_found. A second pass queries versioned IDs (2601.08157v2) to obtain the dates of intermediate versions, needed for revised_dates. Batching resolves 5,000 IDs in about 100 requests instead of 5,000.

Methods considered. The specification lists four discovery tools. OAI-PMH (ListRecords with arXivRaw) returns every version with its date, but a from/until sweep covers every paper modified in the period, far more records than our 25,000, and its resumption tokens expire daily. The Kaggle snapshot is a 4+ GB file refreshed weekly that may miss the newest IDs (m1 is from the current month). S3 holds sources, not metadata. The batched arXiv API gives exactly the assigned IDs, their version count and the dates of every version in minutes, so it is the discovery method; S3 is used later for sources (section 2.3).

2.2 Full-text sources from export.arxiv.org

Each version is downloaded from https://export.arxiv.org/src/<id>v<k> (never from arxiv.org), with a descriptive User-Agent, one connection at a time and at least 3 seconds between requests. The server cuts long transfers of large archives, so a dropped transfer is continued with an HTTP Range request from the last byte received. The status code of every attempt is logged; HTTP 429 and 5xx responses are retried with exponential backoff, and HTTP 404 marks the version missing. The response is spooled in memory and inspected:

  • a tar archive (gzipped or not): only regular .tex and .bib members are extracted, keeping their relative paths so that \input / \include still resolve in Milestone 2; figures and every other file are never written to disk. figure environments and \includegraphics commands are left untouched inside the TeX files;

  • a single gzipped file or a plain file: kept as main.tex if it looks like LaTeX;

  • a PDF or any other format: the version is kept as an empty record (no_tex), not dropped.

Many submissions carry their bibliography only as a compiled .bbl. The crawl keeps .tex and .bib as the specification asks and only counts .bbl files. For Milestone 2, the .bbl of the 2,913 versions that have one but no .bib was fetched afterwards (python -m introds fetch-bbl), so that their references can still be converted to BibTeX.

2.3 Latest versions from the S3 bulk archive

With 3 seconds per request, export.arxiv.org needs at least 6 hours for a range of ~7,000 versions. arXiv also publishes its sources in a requester-pays S3 bucket (s3://arxiv/src/) as monthly tars of ~500 MB, listed in arXiv_src_manifest.xml with the first and last ID of each tar. Each tar holds one gzipped source per paper (2608/2608.28971.gz), as it was when the tar was packed, without a version number. With --s3, the crawler streams the tars that contain the assigned IDs (nothing is stored), infers the version as the latest one submitted before the file’s modification time, and extracts it exactly like a download. Every other version (older versions, revisions after packing) stays pending for export.arxiv.org. verify-s3 re-downloads a random sample from export.arxiv.org and compares every kept file by SHA-256: 15 of 15 matched. The newest month (m1) is not in S3 yet, because tars are added about once a month.

2.4 References

Semantic Scholar’s batch endpoint (POST /graph/v1/paper/batch) returns the references of up to 100 papers per request, with flat field names (references.title, references.authors, references.year, references.publicationDate, references.externalIds). Every reference is kept locally; only those with an externalIds.ArXiv value enter the references table.

2.5 Concurrency, robustness and storage

arXiv and Semantic Scholar are different hosts with separate rate limits, so sources and references run in two threads, each with its own rate limiter. Failed items are retried up to three times, and every 15-20 minutes an incremental backup (SQLite snapshot plus a tar shard of the newly fetched versions) is written so the crawl survives the loss of the Colab VM.

The corpus follows the suggested organisation: one folder per paper (2601-08157) holding one sub-folder per version with its .tex/.bib files, plus metadata.json and references.json.

Tool / libraryUsed for
arxiv (arxiv.py 4)entry discovery through the arXiv API
requestssource downloads, Semantic Scholar batch API
boto3S3 bulk archive (requester pays)
tarfile, gzipin-memory extraction of .tex / .bib
sqlite3crawl state, metadata, timings, resource samples
psutil, GNU timeRAM / disk measurement
pandas, pyarrowstatistics and Parquet export

3. Corpus statistics

Source
Loading...

Definitions. IDs queried includes the IDs probed after the end of a month for a range that crosses a month boundary (m2): discovery stops at the first batch of 100 IDs without any paper. A paper is scraped successfully when every one of its versions was resolved: fetched with TeX, kept as an empty record because arXiv has no TeX source for it, or answered with HTTP 404 by arXiv (missing). Sizes are summed over all versions of a paper: before is the total uncompressed size of every file in the source archives, after is the size of the kept .tex/.bib files. The reference metadata success rate is the share of papers for which Semantic Scholar returned a record with its reference list.

Source
Loading...
Source
<Figure size 770x396 with 1 Axes>
Source
<Figure size 770x396 with 1 Axes>
Loading...
Source
<Figure size 770x396 with 1 Axes>

4. Running time

Times are measured inside the crawler: every unit of work (a discovery batch, an S3 tar, a version download, a Semantic Scholar batch) is timed with time.perf_counter, including rate-limiter waits, and stored in the timings table. The time per paper is the sum of its own downloads plus its share of the batched stages. Wall time covers the crawl command end to end; GNU time -v measures the last (uninterrupted) run of each member independently.

m2, m3, m4 and m5 were crawled with the S3 bulk archive (--s3); m1 only through export.arxiv.org, because its month is not in the bulk archive yet. Wall time is the sum of all runs of a member: a run interrupted by the loss of its Colab VM resumed from its backup, and the time between two runs is not counted. GNU time covers the last run only. During some runs export.arxiv.org throttled requests (HTTP 429), which shows up as longer waits.

Source
Loading...

4.1 Whole team

Each range was crawled independently (one Colab runtime per range). The table adds up the five ranges; elapsed if run in parallel is the longest range, the wall time the team would see with one Colab runtime per member started together.

Source
Loading...
Source
<Figure size 770x396 with 1 Axes>
Loading...

5. Memory footprint

A background thread samples the resident set size (RSS) of the crawler process and its children every 2 seconds with psutil, and the size of the data directory every 60 seconds (the equivalent of du -sb). Samples are stored in the resource_samples table. Benchmark environment: Google Colab, CPU-only runtime (2 vCPU Intel Xeon @ 2.20 GHz, 13.6 GB RAM, Python 3.13).

Source
Loading...
Source
Loading...
Source
<Figure size 770x1430 with 10 Axes>
Loading...

6. Output data

The corpus follows the suggested organisation: one folder per paper, one sub-folder per version with its .tex / .bib files (original relative paths), plus the paper’s metadata and the Semantic Scholar references. The papers and references tables are exported as sharded Parquet for the final dataset (published with Milestone 3).

Source
Loading...
Loading...
Loading...
Loading...
Loading...

7. Limitations

  • Semantic Scholar may lag behind new arXiv uploads; papers it does not know yet are stored as not_found and can be retried with --retry-not-found.

  • Sources whose bibliography exists only as .bbl have no .bib in the Milestone 1 corpus, as the specification asks; their .bbl was fetched separately for Milestone 2.

  • The S3 bulk archive is requester-pays (about USD 1.5 per range) and lags about a month behind arXiv, so it cannot help with the newest month (m1).

  • Versions that still fail after three attempts are kept as failed and counted against the success rate.

8. Requirements checklist

Requirement (Milestone 1 statement)Where
Crawl every version of every assigned paperSections 1, 3 (versions by status)
Full-text sources from export.arxiv.org / S3, figures removed by extraction (.tex, .bib only)2.2, 2.3, Figure 2
Versions without TeX kept as empty records2.2, 3 (no_tex, missing)
Metadata (title, authors, submission and revision dates, venue) and reference metadata2.1, 2.4, 6
Only references with an arXiv ID in references; all references kept locally2.4, 6
Tools and libraries2 (table)
Papers scraped successfully and success rate3
Average paper size before / after figure removal3, Figure 2
Average references per paper; reference metadata success rate3, Figure 3
Total time per paper, average time per paper, entry discovery time, end-to-end wall time4, 4.1, Figure 4
Peak RAM, average RAM, maximum disk usage, final output size5, Figure 5
Auditable measurements on Colab CPU-only4, 5 (perf_counter, psutil, GNU time -v)
Figures and tables generated during book compilationevery figure and table on this page