- HTML 96.6%
- Python 3%
- Typst 0.3%
| abstracts_clean | ||
| abstracts_pdf | ||
| sessions | ||
| tessdata_best | ||
| .gitignore | ||
| abs_urls.txt | ||
| bli | ||
| broken_abstracts.json | ||
| data.json | ||
| extract.py | ||
| fetch_abstracts.sh | ||
| fetch_pages.sh | ||
| gen.py | ||
| index.html | ||
| parse.py | ||
| pre-common.typ | ||
| pre-programme.typ | ||
| programme.md | ||
| programme.pdf | ||
| programme.qmd | ||
| programme_raw.html | ||
| README.md | ||
| requirements.txt | ||
| typst-template.typ | ||
SF2A 2026 — Programme unifié
Pipeline that scrapes the SF2A 2026 conference (Journées de la SF2A, 22–26 June 2026, Grenoble) programme and all session pages, extracts the abstracts from the official PDFs, and regenerates the whole programme as:
index.html— standalone webpage: chronological calendar grid, afternoon parallel sessions side by side per amphitheatre, collapsible abstracts. No external assets; just open it in a browser or drop it on any web server.programme.pdf— full programme with abstracts, typeset via Quarto/Typst (linked from the webpage header).programme.md— same content as plain Markdown.
Everything is regenerable from the SF2A website with the steps below; the intermediate data files are committed so the outputs can also be rebuilt offline from stage 4 onward.
Pipeline
| Stage | Command | Reads | Writes |
|---|---|---|---|
| 1. Fetch pages | ./fetch_pages.sh |
journees.sf2a.eu | programme_raw.html, sessions/s00–s21.html |
| 2. Parse | ./parse.py |
stage 1 output | data.json, abs_urls.txt |
| 3. Fetch abstracts | ./fetch_abstracts.sh |
abs_urls.txt |
abstracts_pdf/*.pdf (191 files) |
| 4. Extract text | ./extract.py |
abstracts_pdf/, tessdata_best/ |
abstracts_clean/*.txt, broken_abstracts.json |
| 5. Generate | ./gen.py |
data.json, abstracts_clean/ |
index.html, programme.md, programme.qmd |
| 6. Render PDF | quarto render programme.qmd |
programme.qmd, *.typ |
programme.pdf |
To reproduce just the webpage, stages 5 alone (./gen.py) is enough — all of
its inputs are in the repo. Run the full chain only to pick up changes from the
SF2A site.
Dependencies
- Python 3 with PyMuPDF
(
pip install -r requirements.txt) — tested with PyMuPDF 1.27 - poppler-utils (
pdftoppm) — rasterises PDFs for OCR - tesseract-ocr ≥ 5 — OCR fallback (language packs not needed; the models
ship in
tessdata_best/, see below) - curl — stages 1 and 3
- Quarto ≥ 1.4 (bundles Typst) — stage 6 only
On Debian/Ubuntu:
sudo apt install poppler-utils tesseract-ocr curl
pip install -r requirements.txt
# Quarto: https://quarto.org/docs/get-started/
How the abstract text is obtained (extract.py)
The goal is the exact published text, so OCR is the last resort:
- Direct extraction (186 of 191 PDFs): the embedded text layer is read in
layout order with PyMuPDF, then TeX-style decomposed accents
(standalone accent glyph before the base letter, e.g.
´e) are recombined into proper composed characters (é). - OCR fallback (4 PDFs): three PDFs have a broken ligature
ToUnicodemap (direct extraction yields garbage) and one has no text layer at all. These are rasterised at 400 dpi and OCRed with the Tesseract best models, French + English. The models intessdata_best/come from tesseract-ocr/tessdata_best (Apache 2.0) and are committed so results are reproducible bit-for-bit. - Broken links (1 PDF): one abstract URL returns an HTML error page; it is
recorded in
broken_abstracts.jsonand shown as "résumé non disponible".
All texts are then reflowed (hard line breaks collapsed, hyphenation at line
ends undone) and, in gen.py, the title/author/affiliation preamble and page
footers are stripped heuristically so only the abstract body is displayed.
Repository layout
fetch_pages.sh stage 1 — download programme + session pages
parse.py stage 2 — HTML → data.json (+ abstract URL list)
fetch_abstracts.sh stage 3 — download abstract PDFs
extract.py stage 4 — PDFs → clean abstract text
gen.py stage 5 — data.json + abstracts → html/md/qmd
typst-template.typ ┐
pre-common.typ ├ Typst styling for the PDF (stage 6)
pre-programme.typ ┘
tessdata_best/ Tesseract 'best' models (fra+eng), for OCR fallback
programme_raw.html ┐
sessions/ ├ scraped inputs (stages 1, 3) — committed for
abstracts_pdf/ ┘ offline reproducibility
data.json ┐
abs_urls.txt ├ intermediates (stages 2, 4)
abstracts_clean/ │
broken_abstracts.json ┘
index.html ┐
programme.md ├ final outputs (stages 5, 6)
programme.qmd │
programme.pdf ┘
Notes & caveats
- Fonts (PDF only):
programme.qmdand the.typfiles reference the licensed "ABC … Edu" font families plus Roboto. If they are not installed, Typst prints "unknown font family" warnings and falls back to its bundled default fonts — the render still succeeds, only the typefaces differ. Edit themainfontline ingen.pyand the fonts inpre-common.typ/pre-programme.typto use your own. - The afternoon room grid (
AFTERNOONinparse.py), evening events and morning notes were transcribed by hand from the published programme grid; if the SF2A reshuffles rooms, update those tables. - Two session pages use header-less tables with their own column layouts;
parse.pyhandles them specially (parse_headerless). - Times are normalised to 24-hour
HH:MM; bare hours below 8 are assumed to be afternoon (the earliest session starts at 09:00). - The scraped pages and abstracts are © their authors / the SF2A; this repo redistributes them solely so the conference programme can be rebuilt.