Parse bank statement PDFs into transaction rows using low-level PDF stream inspection, with optional /ToUnicode decoding for hex-encoded text streams.
This repo now includes realistic synthetic statement PDFs, PNG previews, and parsed output snapshots so you can see exactly what the parser is expected to handle without using any real banking data.
bank_statement_extract.py: parser CLI and library entrypointscripts/generate_synthetic_statements.js: Playwright generator for realistic synthetic statementssamples/pdfs/: generated synthetic PDFssamples/screenshots/: first-page PNG previews rendered from the PDFssamples/parsed/: parser output saved as JSON and CSV
The parser itself uses only the Python standard library, but it depends on qpdf.
macOS with Homebrew:
brew install qpdfUbuntu/Debian:
sudo apt-get update
sudo apt-get install -y qpdfnpm installIf Chrome/Chromium is not in the default macOS location, point Playwright to it explicitly:
export PLAYWRIGHT_CHROMIUM_PATH=/path/to/chrome-or-chromiumParse a statement:
python3 bank_statement_extract.py statement.pdfInspect extracted blocks:
python3 bank_statement_extract.py statement.pdf --debugPrint verbose detection logs:
python3 bank_statement_extract.py statement.pdf --verboseEnable /ToUnicode decoding for hex-encoded text streams:
python3 bank_statement_extract.py statement.pdf --tounicodeExport CSV:
python3 bank_statement_extract.py statement.pdf --csv transactions.csvParse one of the included demo statements:
python3 bank_statement_extract.py samples/pdfs/astra-premier-checking-jan-2026.pdfParse the included demo statements with the wider amount-column thresholds used for the synthetic Chromium PDFs:
python3 bank_statement_extract.py samples/pdfs/astra-premier-checking-jan-2026.pdf \
--amount-columns 420,560,650All sample PDFs in this repository are synthetic. They are meant to document expected layout characteristics, exercise the parser on realistic-looking statements, and provide safe regression artifacts.
Files:
- PDF:
samples/pdfs/astra-premier-checking-jan-2026.pdf - JSON:
samples/parsed/astra-premier-checking-jan-2026.json - CSV:
samples/parsed/astra-premier-checking-jan-2026.csv
Parsed output excerpt:
[
{
"date": "03-01-2026",
"description": "NEFT SALARY CREDIT JAN 2026 ACME ANALYTICS PRIVATE LTD UTR N345601230198",
"deposit": "120000.00",
"withdrawal": "",
"balance": "204913.55"
},
{
"date": "04-01-2026",
"description": "UPI/DR/FRESHMART INDIRANAGAR VPA freshmart@okicici UTR 600412309876",
"deposit": "",
"withdrawal": "2164.75",
"balance": "202748.80"
}
]Files:
- PDF:
samples/pdfs/meridian-salary-account-feb-2026.pdf - JSON:
samples/parsed/meridian-salary-account-feb-2026.json - CSV:
samples/parsed/meridian-salary-account-feb-2026.csv
Parsed output excerpt:
[
{
"date": "01-02-2026",
"description": "UPI/DR/URBAN GROCERS POWAI VPA urbangrocers@okaxis UTR 610112100111",
"deposit": "",
"withdrawal": "1126.40",
"balance": "30715.70"
},
{
"date": "03-02-2026",
"description": "NEFT CR PAYROLL FEB 2026 SKYLINE HEALTH SYSTEMS UTR N441210090021",
"deposit": "92000.00",
"withdrawal": "",
"balance": "122715.70"
}
]Files:
- PDF:
samples/pdfs/northstar-business-current-mar-2026.pdf - JSON:
samples/parsed/northstar-business-current-mar-2026.json - CSV:
samples/parsed/northstar-business-current-mar-2026.csv
Parsed output excerpt:
[
{
"date": "02-03-2026",
"description": "RTGS/CR/CLIENT MILESTONE 02 AURELIA RETAIL GROUP UTR H20260302001",
"deposit": "180000.00",
"withdrawal": "",
"balance": "428510.44"
},
{
"date": "03-03-2026",
"description": "NEFT/DR/STUDIO RENT MARCH ORBIT COMMERCIAL SPACES UTR N20260303088",
"deposit": "",
"withdrawal": "68000.00",
"balance": "360510.44"
}
]- The primary path decodes PDF streams with
qpdf. - For PDFs that store text as hex-encoded glyph runs,
--tounicodelets the parser decode those streams through embedded/ToUnicodemaps while keeping the same stream-order parser. - Supported date formats include
DD-MM-YYYY,DD-MM-YY,DD-MMM-YYYY, andDD-MMM-YY. - If no transactions are detected, start with
--debugand inspect the X/Y placement of the date, description, and amount columns. --amount-columns deposit_min,withdraw_min,balance_minis the compact way to set contiguous amount-column boundaries.- Amount columns can be tuned with
--deposit-x-min,--deposit-x-max,--withdraw-x-min,--withdraw-x-max, and--balance-x-min.
This project is licensed under the MIT License. It is provided as-is, without warranty of any kind. See LICENSE.


