ResumeJSON

Python resume parser: the libraries that work, and the code

If you want a Python resume parser today, the short answer is that the library everyone links to is not maintained, the library that ranks first on GitHub is not the one pip install gives you, and the one tool in this space that is genuinely well kept does not extract resume fields at all. This article is the map: what each option actually returns, the code to run it, and the point where a developer is better off calling a parsing API than owning an NLP stack. Every version and date below was read from PyPI, GitHub or the project's own page as of September 2026.

We build ResumeJSON, a per-parse resume parsing API, so read this as written by an interested party. The library facts are checkable in one pip index — do check them, because the dates are the whole argument.

The Python resume parser libraries, compared

LibraryLatest releasePython support it declaresWhat it returnsMaintained?
pyresparser1.0.6, 15 December 20193.3 – 3.7 (its own classifiers)A fixed dict: name, email, phone, skills, degree, college, designation, companiesNo release in nearly seven years
pydparser1.0.4, 27 December 2023>= 3.10Same shape, plus job-description parsingTwo years since its last release
resume-parser0.8.4, 26 December 2021UnspecifiedA resume dict, spaCy + NLTK basedNearly five years quiet
Docling2.128.0, 16 September 2026>= 3.10, < 4Structured document — headings, tables, reading orderYes, actively
pdfplumber0.11.10, 15 June 2026>= 3.8Raw text, words, tables, character boxesYes
spaCy3.8.16, 24 August 2026>= 3.9, < 3.15Nothing resume-shaped on its own — the NLP toolkit the others build onYes

Two columns do the work here. "Latest release" is the risk you are taking on, because a resume parser is a pile of heuristics about how humans format documents, and those formats keep moving. "What it returns" is the gap you will be filling yourself: the maintained tools give you a clean document, not a candidate record.

The pyresume trap, before you install anything

Search python resume parser and one of the first results is a GitHub repository called pyresume, described as "A simple, accurate resume parser for Python". It is real — wespiper/pyresume, MIT licensed, last pushed 3 August 2025 as of September 2026 — but it is a small project, and more importantly it is not what pip install pyresume installs.

The pyresume package on PyPI is version 0.1.3, uploaded 12 June 2018, from a different author entirely, and its own summary says what it is:

Populate a predefined LaTeX template with contents defined in YAML to build your resume.

That is a résumé builder, not a parser. Two unrelated projects, one name, and the search result and the install command point at different ones. Check the PyPI project URL against the repository you meant before you add anything here to requirements.txt.

What pyresparser actually gives you

pyresparser is the library nearly every tutorial on this topic uses, so it is worth being precise rather than dismissive. Its documented usage is two lines:

from pyresparser import ResumeParser

data = ResumeParser('/path/to/resume/file').get_extracted_data()

What comes back is a dict with a fixed key set — name, email, mobile_number, skills, degree, college_name, designation, company_names, no_of_pages and experience fields. For a screening script that needs a name, an email and a skills list, that is genuinely enough, and 960 GitHub stars say plenty of people shipped it.

The problem is underneath. Its PyPI metadata declares support for Python 3.3 through 3.7, and it depends on spacy (>=2.1.4) with no upper bound — so pip will happily resolve a 2019 library against spaCy 3.8, which changed its pipeline API. Its install instructions ask you to download a spaCy model and NLTK word lists separately, its own notes warn that on Windows you can only extract .docs and .pdf files, and the repository was last pushed 13 September 2023 with 45 issues open. None of that makes it useless. It makes it a 2019 snapshot you are adopting and maintaining, not a dependency somebody else is keeping current for you. Budget for the pinning afternoon before you budget for the parsing.

pydparser is the pragmatic fork of exactly this problem: same shape, and its own summary says it is "compatible with python 3.10". It last released 27 December 2023, so it is the same bet, two years fresher.

Extracting the text is the easy half

A lot of "build a resume parser in Python" tutorials are really PDF-extraction tutorials. That part is solved and well maintained:

import pdfplumber

with pdfplumber.open("resume.pdf") as pdf:
    text = "\n".join(page.extract_text() or "" for page in pdf.pages)

Docling goes further, and its own quickstart is as short:

from docling.document_converter import DocumentConverter

converter = DocumentConverter()
result = converter.convert("resume.pdf")
print(result.document.export_to_markdown())

Docling describes itself as an SDK for "parsing PDF, DOCX, HTML, and more, to a unified document representation" — headings, tables and reading order preserved. It released 2.128.0 on 16 September 2026, which tells you how alive it is compared to everything in the first half of the table.

But notice what you have after either snippet: text. Not work[0].company, not a normalised date range, not a skills array. Turning that text into a candidate record is the part that takes the weeks — name disambiguation, employment date ranges written eleven different ways, education blocks that look exactly like employment blocks, skills that are section headings. That is the half nobody's README covers, and it is the half that decides whether your ATS import is trustworthy.

Who should stay with a Python library

A hosted API is not the right answer for everyone, and there are three cases where staying in-process is clearly correct:

If none of those are you, the calculation changes, because what you are actually buying is somebody else's maintenance of the heuristics.

When calling an API is the cheaper answer

The honest comparison is not library-versus-API on features. It is your time against a per-parse price. A self-hosted stack costs you the spaCy pin, the model downloads in your Docker image, the date-range edge cases, and a re-test every time a resume template trend changes. A parsing API costs a request.

Here is the same job against ResumeJSON, which returns typed JSON — basics, work, education, skills, certifications, languages and total_years_experience — in about 2.2 seconds:

import requests

resp = requests.post(
    "https://resumejson-resume-cv-parser-api.p.rapidapi.com/v1/parse",
    headers={
        "x-rapidapi-key": "YOUR_KEY",
        "x-rapidapi-host": "resumejson-resume-cv-parser-api.p.rapidapi.com",
        "content-type": "application/json",
    },
    json={"text": text},          # or send a file — base64 or multipart
    timeout=30,
)
resume = resp.json()["resume"]
print(resume["basics"]["name"], resume["total_years_experience"])

No model downloads, no spaCy version, nothing to pin. Uploads are accepted to 20 MB and 60,000 characters of text; past either you get a 413 naming the limit rather than a silent truncation.

Self-hosted Python libraryResumeJSON
Setuppip, spaCy model, NLTK data, pinningOne HTTP call
Field mappingYours to write and keepTyped JSON, documented in the field reference
Cost at 100 CVs/monthYour time$0 — the free rung is a hard cap
Cost at 1,000 CVs/monthYour time$29/month, or $0.05 a parse pay-per-use
Keeps working when formats driftIf you maintain itOur problem
Runs offlineYesNo

That last row is the real trade, and it is why the "stay with a library" list above is not a formality.

Try it before you decide

You do not need a key to see the output shape: the free browser parser runs a real CV through the same endpoint, and the field reference is generated from the API's own schema, so it cannot drift from what you will receive. If you are weighing build against buy more broadly, open source resume parser: what works, and when to buy instead covers the non-Python options too, and Textkernel pricing covers the enterprise end of the market.

Whichever way you go, decide it on the release dates rather than the star counts. A parser is a maintenance commitment, and in this corner of PyPI most of the well-known ones stopped being maintained years before the resumes did.

All articles