# Excalibur puts a page-and-box interface in front of Camelot, and stores those boxes for reuse after a long gap at 0.4.x

> Excalibur is an MIT licensed Flask web application that turns Camelot into a browser tool for pulling tables out of PDFs, where you upload a file, draw a box around a table or let it autodetect, and export CSV, Excel, JSON or HTML. It suits a one-person or small team extraction job on text-based PDFs, and scanned documents, ghostscript, and a release history that jumped from 0.4.3 to 1.0 in 2025 are the boundaries.

**camelot-dev/excalibur** — A web interface to extract tabular data from PDFs

- Repository: https://github.com/camelot-dev/excalibur
- Website: https://excalibur-py.readthedocs.io
- Stars: 1,822 · Forks: 240
- Language: Python
- License: MIT
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/camelot-dev-excalibur

## Install ghostscript first, then pip, then two commands

The dependency order matters, and the README puts ghostscript first because Camelot needs it. Once that binary is present, the package install is one line:

```bash
pip install excalibur-py
```

Installing from source is the documented alternative, and it also assumes ghostscript is already in place:

```bash
git clone https://www.github.com/camelot-dev/excalibur
cd excalibur
pip install .
```

Two setup commands come after install, and the first one is easy to miss. The metadata database has to be initialised before the server will start:

```bash
excalibur initdb
excalibur webserver
```

The server then listens on http://localhost:5000. Windows and Linux users who would rather not manage a Python environment can download executables from the releases page and run them directly.

Development installs use an extras group, and the test invocation in the README is the older setuptools form:

```bash
pip install excalibur-py[dev]
python setup.py test
```

That last command is worth flagging. The README heads the section Testing (soon), while pyproject.toml defines the dev extra with pytest, pytest-cov and pytest-runner, and the Makefile runs pytest directly with coverage against the excalibur package. The setup.py path looks like a leftover, and the Makefile target is the one consistent with the declared dependencies.

## Autodetect is a convenience, drawing the box is the control

The workflow starts with an upload and a page number, or a range, naming the pages that hold tables. After that you choose how much of the work to do yourself.

Excalibur renders the page so you can draw a rectangle around the table you want, which is the reliable path. Or you click Autodetect tables and let it find them, and the README suggests using that view to see what Excalibur thinks it can see before committing. That framing is honest: autodetect is a good first attempt and a good diagnostic, but drawing the box is what handles a table that shares a page with body text, a caption or a second table.

Whichever route you take, the result lands on View and download data, where you pick CSV, Excel, JSON or HTML and download. Four formats is a wider choice than most PDF tools offer, and JSON in particular is what makes the output usable by something other than a person.

The whole loop runs in the browser against files on your own machine, with no upload to a third party service. The README states that all file storage and processing happens on your local or remote machine, which is the property that makes this acceptable for documents under an NDA.

## Lattice or Stream is the one decision that changes the result

Under an Advanced heading the extraction flavor is chosen, and the README defines the two options plainly. Lattice is for tables formed with lines. Stream is for tables formed with whitespaces.

This is the setting Camelot exposes, and choosing wrong is the common cause of a bad extraction: a bordered financial table needs Lattice, and a whitespace-aligned report with no ruling lines needs Stream. The README links to Camelot's own comparison with other PDF extraction libraries and tools for what each flavour does in detail, and that page is the right reference when neither works on the first try.

Because Camelot is underneath, the extra settings it offers are reachable from the same interface, which is the argument the README makes for using Excalibur rather than the command line. The useful application of that is saved settings: table areas for a given PDF can be stored once and reapplied to new PDFs with a similar structure. For an organisation that receives the same formatted report every month, that is the feature that turns a one-off extraction into a process.

## Scanned PDFs are out of scope, and the README says so twice

The limitation is stated up front: Excalibur only works with text-based PDFs and not scanned documents. The README borrows the test from Tabula, namely that if you can click and drag to select text in a table in a PDF viewer, the PDF is text-based.

That is a real boundary for anyone whose input is a scanned invoice or a faxed statement. There is no OCR stage here, and pyproject.toml shows no OCR dependency. The documentation site also links to Tabula, which is the natural comparison: The documentation site links to Tabula for the text-based PDF test. For a scanned page you would have to run OCR first and then work with the produced text, and neither tool shortens that path.

## sqlite and multiprocessing by default, MySQL and Celery when the batch grows

Excalibur has a default execution model and a scalable one. By default it uses sqlite for the metadata database and multiprocessing for sequential workloads. It can be configured with MySQL and Celery instead, which the README describes as the path for parallel and distributed workloads.

The dependency list in pyproject.toml backs that up. Celery and SQLAlchemy are both required dependencies, alongside Flask, Werkzeug, click, configparser, pypdfium2 and Pillow, and camelot-py is pinned at 1.0.0 or newer. So the distributed option is not bolted on later; the machinery is present in the default install, and what changes is configuration.

The console entry point is a single script, excalibur = excalibur.cli:cli, which is what makes initdb and webserver available as subcommands rather than as Python functions. Packaging is setuptools based, and the Makefile shows the release path uses twine, while the Windows and Linux executables come from a PyInstaller build of arthur.py that bundles the templates, static files and config templates as data.

## Version 1.0 landed in 2025, after four years at 0.4.x

The release history has a gap in it. Version 0.4.3 is dated 2020-07-17, and then v1.0.0 and v1.0.1 both appear on 2025-01-03, minutes apart. The last push was on 2026-05-20, after that.

So the project went through a long gap between releases, then shipped a 1.0 in a single afternoon and has continued to receive commits since. What the tags do not tell you is how much of the API changed between 0.4 and 1.0, and the README's answer to that is a link to HISTORY.md and the semantic versioning promise, which means you need to read the changelog yourself before upgrading a working 0.4 deployment.

Python support is stated in the classifiers: 3.9 through 3.13, with requires-python set to 3.9 or newer. That is a wide range for a 1.0 that depends on camelot-py 1.0.0 or newer, and it is worth checking the Camelot side of that combination as well.

Licensing is MIT with the text in the LICENSE file, and the project takes one-time or monthly donations through OpenCollective. Supporting organisations are acknowledged on the project's site and in the README.

## Conclusion

Excalibur is a reasonable choice when the person doing the extraction is not the person writing Python, because drawing a box on a rendered page and picking a flavor is a workflow a non-programmer can repeat, and saving table areas for a recurring document shape is the feature that pays off on month two. It is the wrong tool for scanned PDFs, which it cannot read at all, and for anyone who wants a programmatic pipeline, since Camelot is the library underneath and Excalibur only adds the browser around it. Before your first extraction, install ghostscript, run excalibur initdb once, and pick Lattice or Stream deliberately, because the choice between line-formed and whitespace-formed tables decides whether the output is usable.

## FAQ

### How do I install and run Excalibur?

Install ghostscript first, since Camelot requires it, then pip install excalibur-py, run excalibur initdb to initialise the metadata database, and start the server with excalibur webserver. The interface is then at http://localhost:5000.

### Can Excalibur read scanned PDFs?

No. The README states that Excalibur only works with text-based PDFs and not scanned documents, using Tabula's test: if you can click and drag to select text in a PDF viewer, the PDF is text-based. There is no OCR step.

### What is the difference between the Lattice and Stream flavors?

Lattice is for tables formed with lines, Stream is for tables formed with whitespaces. You pick the flavor under Advanced in the web interface, and picking the wrong one is why an extraction comes out unusable.

### Which output formats does Excalibur produce?

CSV, Excel, JSON and HTML, selected after View and download data. Excalibur can also save table extraction settings such as table areas for a PDF and apply them to new PDFs with a similar structure.

### Can Excalibur handle large batches in parallel?

Yes, by configuring MySQL and Celery. The defaults are sqlite and multiprocessing for sequential workloads, and pyproject.toml already lists celery and SQLAlchemy as dependencies, so the distributed path is configuration rather than new code.

## Sources

- [camelot-dev/excalibur on GitHub](https://github.com/camelot-dev/excalibur)
- [License: MIT](https://github.com/camelot-dev/excalibur/blob/master/LICENSE)
- [Project website](https://excalibur-py.readthedocs.io)
- [README](https://github.com/camelot-dev/excalibur/blob/master/README.md)
- [Releases](https://github.com/camelot-dev/excalibur/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/camelot-dev-excalibur
