PDFText
Text extraction like PyMuPDF, but without the AGPL license. PDFText extracts plain text or structured blocks and lines. It's built on pypdfium2, so it's fast, accurate, and Apache licensed.
Community
Discord is where we discuss future development.
Installation
You'll need python 3.9+ first. Then run pip install pdftext.
Usage
- Inspect the settings in
pdftext/settings.py. You can override any settings with environment variables.
Plain text
This command will write out a text file with the extracted plain text.
pdftext PDF_PATH --out_path output.txt
PDF_PATHmust be a single pdf file.--out_pathpath to the output txt file. If not specified, will write to stdout.--sortwill attempt to sort in reading order if specified.--keep_hyphenswill keep hyphens in the output (they will be stripped and words joined otherwise)--page_rangewill specify pages (comma separated) to extract. Like0,5-10,12.--workersspecifies the number of parallel workers to use--flatten_pdfmerges form fields into the PDF
JSON
This command outputs structured blocks and lines with font and other information.
pdftext PDF_PATH --out_path output.txt --json
PDF_PATHmust be a single pdf file.--out_pathpath to the output txt file. If not specified, will write to stdout.--jsonspecifies json output--sortwill attempt to sort in reading order if specified.--page_rangewill specify pages (comma separated) to extract. Like0,5-10,12.--keep_charswill keep individual characters in the json output--workersspecifies the number of parallel workers to use--flatten_pdfmerges form fields into the PDF
The output will be a json list, with each item in the list corresponding to a single page in the input pdf (in order). Each page will include the following keys:
bbox- the page bbox, in[x1, y1, x2, y2]formatrotation- how much the page is rotated, in degrees (0,90,180, or270)page- the index of the pageblocks- the blocks that make up the text in the pdf. Approximately equal to a paragraph.bbox- the block bbox, in[x1, y1, x2, y2]formatlines- the lines inside the blockbbox- the line bbox, in[x1, y1, x2, y2]formatspans- the individual text spans in the line (text spans have the same font/weight/etc)text- the text in the span, encoded in utf-8rotation- how much the span is rotated, in degreesbbox- the span bbox, in[x1, y1, x2, y2]formatchar_start_idx- the start index of the first span character in the pdfchar_end_idx- the end index of the last span character in the pdffontthis is font info straight from the pdf, see this pdfium codesize- the size of the font used for the textweight- font weightname- font name, may be Noneflags- font flags, in the format of thePDF spec 1.7 Section 5.7.1 Font Descriptor Flags
If the pdf is rotated, the bboxes will be relative to the rotated page (they're rotated after being extracted).
Programmatic usage
Extract plain text:
from chunking_contrib.pdftext.extraction import plain_text_output
text = plain_text_output(PDF_PATH, sort=False, hyphens=False, page_range=[1,2,3]) # Optional arguments explained above
Extract structured blocks and lines:
from chunking_contrib.pdftext.extraction import dictionary_output
text = dictionary_output(PDF_PATH, sort=False, page_range=[1,2,3], keep_chars=False) # Optional arguments explained above
Extract text from table cells:
from chunking_contrib.pdftext.extraction import table_output
table_inputs = [
# Each dictionary entry is a single page
{
"tables": [[5,10,10,20]], # Coordinates for tables on the page
"img_size": [512, 512] # The size of the image the tables were detected in
}
]
text = table_output(PDF_PATH, table_inputs, page_range=[1,2,3])
If you want more customization, check out the pdftext.extraction._get_pages function for a starting point to dig deeper. pdftext is a pretty thin wrapper around pypdfium2, so you might want to look at the documentation for that as well.
Benchmarks
I benchmarked extraction speed and accuracy of pymupdf, pdfplumber, and pdftext. I chose pymupdf because it extracts blocks and lines. Pdfplumber extracts words and bboxes. I did not benchmark pypdf, even though it is a great library, because it doesn't provide individual character/line/block and bbox information.
Here are the scores, run on an M1 Macbook, without multiprocessing:
| Library | Time (s per page) | Alignment Score (% accuracy vs pymupdf) |
|---|---|---|
| pymupdf | 0.32 | -- |
| pdftext | 1.36 | 97.78 |
| pdfplumber | 3.16 | 90.36 |
pdftext is approximately 2x slower than using pypdfium2 alone (if you were to extract all the same character information).
There are additional benchmarks for pypdfium2 and other tools here.
Methodology
I used a benchmark set of 200 pdfs extracted from common crawl, then processed by a team at HuggingFace.
For each library, I used a detailed extraction method, to pull out font information, as well as just the words. This ensured we were comparing similar performance numbers. I formatted the text similarly when extracting - newlines after lines, and double newlines after blocks. For pdfplumber, I could only do the newlines after lines, since it doesn't recognize blocks.
For the alignment score, I extracted the text, then used the rapidfuzz library to find the alignment percentage. I used the text extracted by pymupdf as the pseudo-ground truth.
Running benchmarks
You can run the benchmarks yourself. To do so, you have to first install pdftext manually. The install assumes you have poetry and Python 3.9+ installed.
git clone https://github.com/VikParuchuri/pdftext.git
cd pdftext
poetry install
python benchmark.py # Will download the benchmark pdfs automatically
The benchmark script has a few options:
--maxthis controls the maximum number of pdfs to benchmark--result_patha folder to save the results. A file calledresults.jsonwill be created in the folder.--pdftext_onlyskip running pdfplumber, which can be slow.
How it works
PDFText is a very light wrapper around pypdfium2. It first uses pypdfium2 to extract characters in order, along with font and other information. Then it uses a simple decision tree algorithm to group characters into lines and blocks. It does some simple postprocessing to clean up the text.
Credits
This is built on some amazing open source work, including:
- pypdfium2
- scikit-learn
- pypdf for very thorough and fair benchmarks
Thank you to the pymupdf devs for creating such a great library - I just wish it had a simpler license!
Metadata
Release files for chunking-pdftext 0.6.2.post2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| chunking_pdftext-0.6.2.post2.tar.gz | 22.1 kB | Without provenance | Details for chunking_pdftext-0.6.2.post2.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| chunking_pdftext-0.6.2.post2-py3-none-any.whl | Python 3 | none | any | Details for chunking_pdftext-0.6.2.post2-py3-none-any.whl |
Total release size: 46.4 kB
Release files / chunking_pdftext-0.6.2.post2.tar.gz
| Download URL | chunking_pdftext-0.6.2.post2.tar.gz |
|---|---|
| Size | 22.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6dd2df3cefc2d9e052d3b99c05bcf465296649c4631bfbb588541b82c4441fde
|
|
BLAKE2b-256 checksum How to use checksums |
a537f55e91223706b683768b046c36fbb8d2dfc8dae663b21a0329da25e470d9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.10.16
|
Release files / chunking_pdftext-0.6.2.post2-py3-none-any.whl
| Download URL | chunking_pdftext-0.6.2.post2-py3-none-any.whl |
|---|---|
| Size | 24.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f885fd3184a7948be93d704db1c83e5abac0f439cdbebaa6b3e91176264be401
|
|
BLAKE2b-256 checksum How to use checksums |
3fc4a2a9fe5bd5dbfe3ffa14ff8e70fc93c837c77952baa5b375479dbcff334a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.10.16
|
Security for chunking-pdftext 0.6.2.post2
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.