> Source: https://txtfetch.com/for/python > Plain-text twin — every page on txtfetch.com has one. https://txtfetch.com/text --- # Python's parser zoo, replaced by one POST. pypdf handles PDFs. python-docx handles Word. openpyxl handles Excel. extract-msg handles Outlook. pytesseract handles scans. That's five libraries, five APIs, and five sets of edge cases. txtfetch is one. the-parser-zoo Python has the deepest document-parsing ecosystem of any language. That is also the problem. Covering PDF, Office, email, and scans means installing and maintaining five separate libraries. Each one has its own API and its own blind spot. pypdf reads digital-native PDF text cleanly, but it has no OCR path and struggles with multi-column layouts and dense tables. python-docx is OOXML-only. A .docx file works. But a .doc file from 2009 throws an error before you get a single character back. And python-docx has nothing at all for .pptx or .xlsx. openpyxl reads .xlsx cells directly. But formula cells need data\_only=True to get the calculated value instead of the =SUM() string. That cached value only exists if Excel itself last saved the file. A workbook produced by another tool can hand back None instead. pytesseract is not really an OCR library. It is a thin wrapper that shells out to a system tesseract binary. You have to install that binary yourself and keep it on PATH. You also need Pillow for images, and pdf2image (which itself needs poppler-utils) if the scan is a PDF rather than a bare image. | library | covers | stops at | | --- | --- | --- | | `pypdf` | Digital-native PDF text extraction | No OCR; struggles with multi-column layouts and dense tables | | `python-docx` | .docx paragraphs, tables, and headers | OOXML only — no legacy .doc, and nothing for .pptx or .xlsx | | `openpyxl` | .xlsx cell values, including shared strings | Formula cells need data\_only=True plus a prior Excel save — no live recalculation; no .xls | | `extract-msg` | Outlook .msg header and body parsing | Only .msg — no .pst/.ost mailbox archives, and nothing outside email | | `pytesseract` | OCR, once paired with Pillow and a system Tesseract install | You install, update, and package the tesseract binary yourself; PDFs need pdf2image + poppler on top | one-request txtfetch replaces the imports, not just the parsing. One POST does the job: send a multipart file, or pass ?url=. Either way you get back { "status": "success", "extracted\_text": "..." }. That is true whether the source was a pypdf-shaped PDF, a python-docx-shaped .docx, an openpyxl-shaped .xlsx, or a pytesseract-shaped scan. The official txtfetch Python SDK wraps the same call in a typed client, with exceptions per error code. A single try/except replaces the format-detection branching a hand-rolled pipeline needs before it can even pick which library to call. Python ```python import os import requests with open("report.pdf", "rb") as f: r = requests.post( "https://api.txtfetch.com/v1/extract", headers={"Authorization": f"Bearer {os.environ['TXTFETCH_KEY']}"}, files={"file": f}, ) print(r.json()["extracted_text"]) ``` ``` { "status": "success", "extracted_text": "..." } ``` txtfetch (Python SDK) pip install txtfetch. One client class, with typed exceptions per error code, and no per-format branching. Install ```install pip install txtfetch ``` Quickstart ```quickstart from txtfetch import Txtfetch # api_key defaults to the TXTFETCH_KEY environment variable client = Txtfetch(api_key="tf_live_...") # Extract from a local file (path, bytes, or a file-like object all work) result = client.extract(file="whitepaper.pdf") print(result.extracted_text) print(result.metadata.content_type, result.metadata.bytes, result.metadata.ocr) # Extract from a URL — txtfetch fetches it server-side result = client.extract(url="https://example.com/whitepaper.docx") ``` from-a-url Skip the download entirely. Pass a `url` parameter and txtfetch fetches the document server-side: Python ```python import os import requests r = requests.post( "https://api.txtfetch.com/v1/extract", headers={"Authorization": f"Bearer {os.environ['TXTFETCH_KEY']}"}, params={"url": "https://example.com/report.pdf"}, ) print(r.json()["extracted_text"]) ``` errors Every non-success response carries a stable `error.code`. Match on that, not on `error.message`. See the full [error reference](https://txtfetch.com/docs/errors) for every code and HTTP status txtfetch can return. Python ```python import os import requests with open("report.pdf", "rb") as f: r = requests.post( "https://api.txtfetch.com/v1/extract", headers={"Authorization": f"Bearer {os.environ['TXTFETCH_KEY']}"}, files={"file": f}, ) if r.status_code == 200: print(r.json()["extracted_text"]) elif r.status_code == 429: code = r.json()["error"]["code"] # "rate_limited", "quota_exceeded", or "abuse_detected" print(f"back off: {code}, retry after {r.headers['Retry-After']}s") else: error = r.json()["error"] print(f"extraction failed: {error['code']} — {error['message']}") ``` big-files-and-batches Large uploads or slow documents are routed to an async job automatically. That returns a `202` plus a `job_id` to poll, and `?async=true` forces that path for any request. Direct upload size ceilings by plan: Hobby 10 MB, Developer 50 MB, Scale 200 MB. Use `?url=` for anything larger. Server-side fetches aren't held to the upload ceiling. See [async jobs & webhooks](https://txtfetch.com/docs/async) for the full lifecycle, including webhook delivery instead of polling. Python ```python import os import time import requests HEADERS = {"Authorization": f"Bearer {os.environ['TXTFETCH_KEY']}"} submit = requests.post( "https://api.txtfetch.com/v1/extract", headers=HEADERS, params={"url": "https://example.com/report.pdf", "async": "true"}, ) job_id = submit.json()["job_id"] while True: poll = requests.get(f"https://api.txtfetch.com/v1/extract/{job_id}", headers=HEADERS) result = poll.json() if result["status"] != "processing": break time.sleep(2) print(result["extracted_text"]) ``` gotchas - pip install pytesseract installs a Python wrapper, not an OCR engine. It does not install the tesseract binary itself. Without that binary on PATH, every call fails at runtime, not at import time. The error reads "tesseract is not installed or it's not in your PATH". - openpyxl's data\_only=True reads Excel's last cached calculation, not a live recalculation. A workbook written by a script that never opened it in Excel can have an empty cache. A perfectly valid formula cell can then read back as None. - pandas.read\_csv guesses UTF-8 by default. A Windows-1252 export with curly quotes or em dashes mojibakes silently, unless you pass the correct encoding= yourself. - python-docx, python-pptx, and openpyxl are three separate PyPI packages. Each has its own object model, for what marketing calls "just Office files". No single import spans the whole family. formats - [PDF](https://txtfetch.com/extract/pdf) - [Word / PowerPoint / Excel](https://txtfetch.com/extract/docx) - [Excel formulas & tables](https://txtfetch.com/extract/xlsx) - [Scans & images (OCR)](https://txtfetch.com/extract/image) - [Outlook .msg](https://txtfetch.com/extract/msg) faq **How do I extract text from a PDF in Python without pypdf or pdfplumber?**: POST the file to https://api.txtfetch.com/v1/extract (multipart, or ?url= for a remote PDF), with your API key in the Authorization header. Or use the txtfetch Python SDK's client.extract(file="..."). Either way you get back { "status": "success", "extracted_text": "..." }, whether the PDF is digital-native or scanned. There is no pypdf or pdfplumber import, and no separate OCR branch to write. **Can I OCR a scanned document in Python without installing Tesseract myself?**: Yes. POST the scan (PNG, JPG, TIFF, or a scanned PDF) to txtfetch, and OCR runs server-side automatically. There's no tesseract binary to install, no PATH to configure, and no pytesseract/Pillow/pdf2image chain to keep working across OS upgrades. **How do I read an Outlook .msg file in Python?**: extract-msg works, but it only covers .msg. txtfetch's Python SDK handles .msg the same way as every other format, with client.extract(file="thread.msg"). It also covers whole .pst/.ost mailbox archives through the same call, which extract-msg doesn't. **Does openpyxl's data_only=True always give me the calculated cell value?**: Only if Excel itself last saved the workbook. data_only=True reads a cached result, and that cache can be empty for files produced by other tools. txtfetch returns the same cached calculated value, with no data_only= flag to remember and no separate code path per format. But txtfetch reads Excel's cache too. A workbook whose formulas were never calculated by a spreadsheet app has no stored result for either tool to find. **Is there an official Python SDK for txtfetch?**: Yes. pip install txtfetch. Its only runtime dependency is httpx, and it maps every API error code to its own typed exception class (see /docs/quickstarts). go-further - [txtfetch (Python SDK) quickstart →](https://txtfetch.com/docs/quickstarts) - [Using txtfetch as a LangChain and LlamaIndex document loader →](https://txtfetch.com/blog/langchain-llamaindex-document-loader) - [RAG & LLM ingestion pipelines →](https://txtfetch.com/solutions/rag-ingestion) - [Measured extraction accuracy by category →](https://txtfetch.com/benchmarks) - [API quickstart →](https://txtfetch.com/docs) - [How the pipeline works →](https://txtfetch.com/how-it-works) - [Get an API key →](https://app.txtfetch.com/signup) other-languages - [`JavaScript`](https://txtfetch.com/for/javascript) - [`Go`](https://txtfetch.com/for/go) - [`Java`](https://txtfetch.com/for/java) - [`C# / .NET`](https://txtfetch.com/for/csharp) - [All languages →](https://txtfetch.com/for) ## Paste it into your project. The Python snippet above runs as written. Add your key and it works. [Get an API key →](https://app.txtfetch.com/signup) [More SDK quickstarts →](https://txtfetch.com/docs/quickstarts)