A tiny, dependency-free Python package that takes the plain text of a resume (or any document with headed sections) and pulls out sections, emails, phone numbers, name candidates and a skills list.
In March 2025 I was building a CV-screening tool and could not find a small open source package that just did the boring text parts of resume parsing without dragging in spaCy or a model download. So I wrote the handful of regex and line heuristics I needed as an installable package with tests, so I could reuse it across projects.
Realistic use: you already have the text of a document (from PyPDF2, python-docx, OCR, a form field) and want a first-pass structure out of it, cheaply and deterministically, before doing anything smarter.
git clone https://github.com/joelstephen97/doc_parser.git
cd doc_parser
pip install -e .
python -m unittest discover -s tests # 8 testsfromdoc_parserimportDocumentParsertext=open("resume.txt", encoding="utf-8").read()
doc=DocumentParser(text)
doc.extract_emails() # ['jane.roe@example.com']doc.extract_phone_numbers() # ['+971568098085']doc.extract_skills() # ['Python', 'FastAPI', 'PostgreSQL', 'Docker']doc.return_sections() # {'GENERAL': 'Jane Roe ...', 'SUMMARY': '...', 'SKILLS': '...'}doc.search("Python") # ['developer with five years in Python services. SKILLS Python, ...']doc.extract_name() # ['Jane Roe', 'SUMMARY', 'Backend', ...] (candidates, see below)Or from the shell:
doc-parser resume.txt --search Python # or: python -m doc_parser resume.txt
doc-parser notes.txt --sections INTRODUCTION,BODY,CONCLUSIONThe CLI prints one JSON object with emails, phone_numbers, name_candidates, skills, sections and, if asked, search.
DocumentParser(text, clean=True)
clean_text(text): collapses newlines and repeated whitespace. Applied on init unlessclean=False; the original is kept in.original_text.return_sections(custom_sections=None): walks the original lines; a line is a header if it is in the section set (defaults: OBJECTIVE, SUMMARY, EXPERIENCE, EDUCATION, SKILLS, PROJECTS, CERTIFICATIONS, AWARDS, EXTRACURRICULAR) or if it is all upper-case and at most four words. Text before the first header lands inGENERAL. Pass your ownsetof upper-case headers for non-resume documents.search(keyword): case-insensitive substring match per word, returns snippets of five words either side.extract_emails(): regex.extract_phone_numbers(): keeps+1 (555) 123-4567style numbers as written, normalises other+numbers to digits only, and picks up bare 10-digit numbers.extract_name(): returns every Title Case / ALL CAPS run in the original text. It is a candidate list, not an answer: section headers and capitalised nouns come back too. In practice the first candidate on a resume is usually the name.extract_skills(): splits theSKILLSsection on commas.
Everything is re and string handling in one file, doc_parser/parser.py. There is no model, no network, no dependency. That is the point: it is predictable and fast, and it is easy to read the whole thing in five minutes and adjust a pattern.
- Verified August 2026:
pip install -e .thenpython -m unittest discover -s testsruns 8 tests, all pass, on Python 3.12. - Heuristics only. Headers that are not upper-case, skills listed with bullets instead of commas, and names in lower case will be missed.
extract_nameover-matches by design (the TODO in the code is real). - Input must already be text; PDF/DOCX/OCR extraction is out of scope here (see my
cv_analysisrepo for that end of the pipeline). - Not on PyPI; install from the repo.
MIT, see LICENSE.