Use when reading, creating, editing, merging, splitting, or extracting content from PDF files or Excel/spreadsheet files. Use when processing tabular data, building financial models in Excel, extracting text from scanned documents, or converting between document formats. Triggers: "PDF", "Excel", "spreadsheet", "xlsx", "pypdf", "pdfplumber", "reportlab", "openpyxl", "pandas", "document processing", "extract text from PDF", "merge PDF", "split PDF", "financial model", "OCR", "spreadsheet automation".
Create PDFs from scratch (canvas or document flow)
pip install reportlab
pytesseract
OCR on scanned/image-only PDFs
pip install pytesseract pdf2image
Merge PDFs with pypdf
from pypdf import PdfWriter, PdfReader
writer = PdfWriter()
for pdf_file in ["doc1.pdf", "doc2.pdf", "doc3.pdf"]:
reader = PdfReader(pdf_file)
for page in reader.pages:
writer.add_page(page)
with open("merged.pdf", "wb") as f:
writer.write(f)
Extract Table with pdfplumber
import pdfplumber
import pandas as pd
with pdfplumber.open("document.pdf") as pdf:
all_tables = []
for page in pdf.pages:
for table in page.extract_tables():
if table:
df = pd.DataFrame(table[1:], columns=table[0])
all_tables.append(df)
combined = pd.concat(all_tables, ignore_index=True)
combined.to_excel("extracted_tables.xlsx", index=False)
Create PDF with reportlab
from reportlab.lib.pagesizes import letter
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer
from reportlab.lib.styles import getSampleStyleSheet
doc = SimpleDocTemplate("report.pdf", pagesize=letter)
styles = getSampleStyleSheet()
story = [
Paragraph("Report Title", styles['Title']),
Spacer(1, 12),
Paragraph("Body content goes here.", styles['Normal']),
]
doc.build(story)
ReportLab subscripts/superscripts: Never use Unicode characters (₀₁₂, ⁰¹²) — built-in fonts render them as black boxes. Use XML tags instead: H<sub>2</sub>O, x<super>2</super>.
OCR Pattern with pytesseract
import pytesseract
from pdf2image import convert_from_path
images = convert_from_path("scanned.pdf")
text = ""
for i, image in enumerate(images):
text += f"--- Page {i+1} ---\n"
text += pytesseract.image_to_string(image) + "\n\n"
print(text)
After saving, run python scripts/recalc.py output.xlsx to recalculate and detect #REF!, #DIV/0!, #VALUE!, #NAME?
Quick Reference
Task
Best Tool
Command / Code
Merge PDFs
pypdf
writer.add_page(page) for each file
Extract tables from PDF
pdfplumber
page.extract_tables()
Create PDF from scratch
reportlab
SimpleDocTemplate + Platypus story
OCR scanned PDF
pytesseract
convert_from_path then image_to_string
CLI merge
qpdf
qpdf --empty --pages f1.pdf f2.pdf -- out.pdf
Read/analyze spreadsheet
pandas
pd.read_excel("file.xlsx", sheet_name=None)
Format/formula spreadsheet
openpyxl
load_workbook + assign "=FORMULA" strings
Recalculate & error-check
LibreOffice
python scripts/recalc.py output.xlsx
Verification Checklist
PDF
Correct library chosen for the task (merge → pypdf, extract → pdfplumber, create → reportlab)
Output file opens without errors and page count is correct
No Unicode subscript/superscript characters used in reportlab Paragraphs
OCR output spot-checked against source image for accuracy
Spreadsheet
Zero formula errors: #REF!, #DIV/0!, #VALUE!, #NAME? all absent
All calculations use Excel formulas, not Python-hardcoded values
Financial model color coding applied (blue inputs, black formulas, green cross-sheet)
Number formats match standards (currency units in headers, zeros as −, negatives in parentheses)
scripts/recalc.py run after saving and output shows "status": "success"
Cell references verified for row offset (DataFrame → Excel is 1-indexed)
Hardcoded source values documented with Source comment (system, date, reference)
1---2name: document-processing3description: Use when reading, creating, editing, merging, splitting, or extracting content from PDF files or Excel/spreadsheet files. Use when processing tabular data, building financial models in Excel, extracting text from scanned documents, or converting between document formats. Triggers: "PDF", "Excel", "spreadsheet", "xlsx", "pypdf", "pdfplumber", "reportlab", "openpyxl", "pandas", "document processing", "extract text from PDF", "merge PDF", "split PDF", "financial model", "OCR", "spreadsheet automation".4---56# Document Processing78## When to Use910- User wants to read, create, edit, merge, split, rotate, watermark, or extract content from PDF files11- User wants to open, read, edit, create, or format Excel/spreadsheet files (.xlsx, .xlsm, .csv, .tsv)12- User needs to build a financial model, clean tabular data, or automate spreadsheet generation13- User needs OCR on scanned documents or table extraction from PDFs14- User asks to convert between document formats where the output is a PDF or spreadsheet file1516## When NOT to Use1718- Database ingestion pipelines or ETL workflows → use `data-engineering`19- Log file parsing, monitoring dashboards, or structured log analysis → use `observability`20- Primary deliverable is a Word document, HTML report, or standalone Python script21- Google Sheets API integration (no local file involved)2223---2425## PDF Processing2627### Library Selection2829| Library | Best For | Install |30|---|---|---|31| `pypdf` | Merge, split, rotate, metadata, watermark, encrypt | `pip install pypdf` |32| `pdfplumber` | Text extraction with layout, table extraction | `pip install pdfplumber` |33| `reportlab` | Create PDFs from scratch (canvas or document flow) | `pip install reportlab` |34| `pytesseract` | OCR on scanned/image-only PDFs | `pip install pytesseract pdf2image` |3536### Merge PDFs with pypdf3738```python39from pypdf import PdfWriter, PdfReader4041writer = PdfWriter()42for pdf_file in ["doc1.pdf", "doc2.pdf", "doc3.pdf"]:43 reader = PdfReader(pdf_file)44 for page in reader.pages:45 writer.add_page(page)4647with open("merged.pdf", "wb") as f:48 writer.write(f)49```5051### Extract Table with pdfplumber5253```python54import pdfplumber55import pandas as pd5657with pdfplumber.open("document.pdf") as pdf:58 all_tables = []59 for page in pdf.pages:60 for table in page.extract_tables():61 if table:62 df = pd.DataFrame(table[1:], columns=table[0])63 all_tables.append(df)6465combined = pd.concat(all_tables, ignore_index=True)66combined.to_excel("extracted_tables.xlsx", index=False)67```6869### Create PDF with reportlab7071```python72from reportlab.lib.pagesizes import letter73from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer74from reportlab.lib.styles import getSampleStyleSheet7576doc = SimpleDocTemplate("report.pdf", pagesize=letter)77styles = getSampleStyleSheet()78story = [79 Paragraph("Report Title", styles['Title']),80 Spacer(1, 12),81 Paragraph("Body content goes here.", styles['Normal']),82]83doc.build(story)84```8586> **ReportLab subscripts/superscripts**: Never use Unicode characters (₀₁₂, ⁰¹²) — built-in fonts render them as black boxes. Use XML tags instead: `H<sub>2</sub>O`, `x<super>2</super>`.8788### OCR Pattern with pytesseract8990```python91import pytesseract92from pdf2image import convert_from_path9394images = convert_from_path("scanned.pdf")95text = ""96for i, image in enumerate(images):97 text += f"--- Page {i+1} ---\n"98 text += pytesseract.image_to_string(image) + "\n\n"99print(text)100```101102### CLI Alternatives103104| Tool | One-liner |105|---|---|106| `pdftotext` | `pdftotext -layout input.pdf output.txt` |107| `qpdf` | `qpdf --empty --pages file1.pdf file2.pdf -- merged.pdf` |108| `pdftk` | `pdftk file1.pdf file2.pdf cat output merged.pdf` |109110---111112## Spreadsheet Processing113114### pandas vs openpyxl115116| Need | Use |117|---|---|118| Bulk data analysis, statistics, CSV/Excel read for analysis | `pandas` |119| Formatting, formulas, color coding, cell-level control | `openpyxl` |120121```python122import pandas as pd123124df = pd.read_excel("file.xlsx", sheet_name=None) # All sheets as dict125df["Sheet1"].describe()126df["Sheet1"].to_excel("output.xlsx", index=False)127```128129```python130from openpyxl import Workbook, load_workbook131from openpyxl.styles import Font, PatternFill, Alignment132133wb = load_workbook("existing.xlsx")134ws = wb.active135136ws["A1"] = "Label"137ws["B1"] = "=SUM(B2:B10)" # Always formulas, never hardcoded values138ws["A1"].font = Font(bold=True, color="000000")139ws.column_dimensions["A"].width = 20140141wb.save("output.xlsx")142```143144> **Warning**: Loading with `data_only=True` then saving permanently replaces formulas with static values.145146### Formula-First Philosophy147148Never hardcode computed values in Python — let Excel calculate them. The spreadsheet must recalculate when source data changes.149150```python151# WRONG152sheet["B10"] = df["Sales"].sum() # Hardcodes 5000153154# CORRECT155sheet["B10"] = "=SUM(B2:B9)" # Excel owns the calculation156sheet["C5"] = "=(C4-C2)/C2" # Growth rate as formula157sheet["D20"] = "=AVERAGE(D2:D19)" # Average as formula158```159160### Financial Model Color Coding161162| Color | RGB | Meaning |163|---|---|---|164| Blue text | `0,0,255` | Hardcoded inputs / scenario drivers |165| Black text | `0,0,0` | All formulas and calculations |166| Green text | `0,128,0` | Links to other worksheets in same workbook |167| Red text | `255,0,0` | External links to other files |168| Yellow background | `255,255,0` | Key assumptions needing attention |169170### Number Formatting Standards171172| Type | Format | Example |173|---|---|---|174| Currency | `$#,##0` with units in header | `Revenue ($mm)` |175| Zeros | `$#,##0;($#,##0);-` | Displays as `−` |176| Percentages | `0.0%` | `12.5%` |177| Multiples | `0.0x` | `8.5x` |178| Negatives | Parentheses | `(123)` not `-123` |179| Years | Text string | `"2024"` not `2,024` |180181### Formula Verification182183Before building the full model, test 2–3 sample cell references manually. Then verify:184185- NaN handling: `pd.notna(value)` before writing references186- Division by zero: wrap denominators (`=IF(B5=0, 0, A5/B5)`)187- Row indexing: DataFrame row 5 = Excel row 6 (1-indexed)188- Cross-sheet references: `=Sheet1!A1` format189- After saving, run `python scripts/recalc.py output.xlsx` to recalculate and detect `#REF!`, `#DIV/0!`, `#VALUE!`, `#NAME?`190191---192193## Quick Reference194195| Task | Best Tool | Command / Code |196|---|---|---|197| Merge PDFs | pypdf | `writer.add_page(page)` for each file |198| Extract tables from PDF | pdfplumber | `page.extract_tables()` |199| Create PDF from scratch | reportlab | `SimpleDocTemplate` + `Platypus` story |200| OCR scanned PDF | pytesseract | `convert_from_path` then `image_to_string` |201| CLI merge | qpdf | `qpdf --empty --pages f1.pdf f2.pdf -- out.pdf` |202| Read/analyze spreadsheet | pandas | `pd.read_excel("file.xlsx", sheet_name=None)` |203| Format/formula spreadsheet | openpyxl | `load_workbook` + assign `"=FORMULA"` strings |204| Recalculate & error-check | LibreOffice | `python scripts/recalc.py output.xlsx` |205206---207208## Verification Checklist209210### PDF211- [ ] Correct library chosen for the task (merge → pypdf, extract → pdfplumber, create → reportlab)212- [ ] Output file opens without errors and page count is correct213- [ ] No Unicode subscript/superscript characters used in reportlab Paragraphs214- [ ] OCR output spot-checked against source image for accuracy215216### Spreadsheet217- [ ] Zero formula errors: `#REF!`, `#DIV/0!`, `#VALUE!`, `#NAME?` all absent218- [ ] All calculations use Excel formulas, not Python-hardcoded values219- [ ] Financial model color coding applied (blue inputs, black formulas, green cross-sheet)220- [ ] Number formats match standards (currency units in headers, zeros as `−`, negatives in parentheses)221- [ ] `scripts/recalc.py` run after saving and output shows `"status": "success"`222- [ ] Cell references verified for row offset (DataFrame → Excel is 1-indexed)223- [ ] Hardcoded source values documented with Source comment (system, date, reference)
Run npx skillmds@latest add thejordanleopold/document-processing in your terminal (requires Node.js), paste this page's agent-chat prompt into Claude, Cursor, or any MCP-connected agent, or download the SKILL.md file and copy it into your agent's skills directory.
Use when reading, creating, editing, merging, splitting, or extracting content from PDF files or Excel/spreadsheet files. Use when processing tabular data, building financial models in Excel, extracting text from scanned documents, or converting between document formats. Triggers: "PDF", "Excel", "spreadsheet", "xlsx", "pypdf", "pdfplumber", "reportlab", "openpyxl", "pandas", "document processing", "extract text from PDF", "merge PDF", "split PDF", "financial model", "OCR", "spreadsheet automation". It is listed under Data & Analytics on SkillMD.
This skill has not completed SkillMD's automated safety review yet. Capability flags: docs only. SkillMD never runs a skill's scripts for you; review the SKILL.md before installing.
This skill is tagged as working with Claude Code, Claude.ai, OpenAI Codex. SKILL.md is an open format, so most agents that read a skills directory can load it too.
Yes. Installing skills from SkillMD is free, and the skill stays under its author's original license.
thejordanleopold (@thejordanleopold) published this skill. Their other Agent Skills are listed on their SkillMD profile.