1 · PDF to Markdown with images as files#
from pathlib import Path
from docling.datamodel.base_models import InputFormat
from docling.datamodel.pipeline_options import PdfPipelineOptions
from docling.document_converter import DocumentConverter, PdfFormatOption
from docling_core.types.doc import ImageRefMode
opts = PdfPipelineOptions(do_ocr=False, generate_picture_images=True, images_scale=2.0)
converter = DocumentConverter(format_options={InputFormat.PDF: PdfFormatOption(pipeline_options=opts)})
doc = converter.convert("report.pdf").document
out = Path("out"); out.mkdir(exist_ok=True)
doc.save_as_markdown(out / "report.md", artifacts_dir=Path("images"), image_mode=ImageRefMode.REFERENCED)
print(sorted(p.name for p in (out / "images").glob("*.png"))[:3])Pictures are written as PNG files into out/images and linked from the Markdown with relative paths. A relative artifacts_dir is resolved against the Markdown file's folder — if you leave it out and save into a subfolder, docling-core 2.106.0 nests the images one level deeper (out/out/report_artifacts), which surprised us in testing.
2 · Convert a whole folder, survive bad files, write a report#
import csv
from pathlib import Path
from docling.datamodel.base_models import ConversionStatus
from docling.document_converter import DocumentConverter
src, out = Path("inbox"), Path("out")
out.mkdir(exist_ok=True)
converter = DocumentConverter()
with open(out / "report.csv", "w", newline="") as f:
log = csv.writer(f)
log.writerow(["file", "status", "pages", "seconds"])
files = [p for p in src.iterdir() if p.is_file()]
for res in converter.convert_all(files, raises_on_error=False):
name = res.input.file.name
if res.status in (ConversionStatus.SUCCESS, ConversionStatus.PARTIAL_SUCCESS):
res.document.save_as_markdown(out / f"{res.input.file.stem}.md")
secs = sum(sum(t.times) for k, t in res.timings.items() if k == "pipeline_total")
log.writerow([name, res.status.value, len(res.pages), round(secs, 1)])pipeline_total is only filled when profiling is on (settings.debug.profile_pipeline_timings = True); otherwise the seconds column is 0.
3 · Every table to CSV and one Excel workbook#
import pandas as pd
from docling.document_converter import DocumentConverter
doc = DocumentConverter().convert("report.pdf").document
with pd.ExcelWriter("tables.xlsx") as xls:
for i, table in enumerate(doc.tables, start=1):
df = table.export_to_dataframe(doc=doc)
df.to_csv(f"table_{i}.csv", index=False)
df.to_excel(xls, sheet_name=f"table_{i}", index=False)
print(i, df.shape, "page", table.prov[0].page_no)openpyxl, which pandas uses to write .xlsx, is installed with Docling.
4 · One Markdown file per page#
from docling.document_converter import DocumentConverter
doc = DocumentConverter().convert("report.pdf").document
for page_no in sorted(doc.pages):
md = doc.export_to_markdown(page_no=page_no)
with open(f"page_{page_no:03d}.md", "w") as f:
f.write(md)
print(len(doc.pages), "pages written")5 · Find pages that need a human look#
Each ConversionResult carries a confidence report with parse, layout, table and OCR scores per page and an overall grade (poor, fair, good or excellent).
from docling.document_converter import DocumentConverter
res = DocumentConverter().convert("report.pdf")
conf = res.confidence
print("document:", conf.mean_grade.value, round(conf.mean_score, 3))
for page_no, scores in sorted(conf.pages.items()):
print(page_no, scores.mean_grade.value, round(scores.layout_score, 3))6 · Figures with their captions#
from docling.datamodel.base_models import InputFormat
from docling.datamodel.pipeline_options import PdfPipelineOptions
from docling.document_converter import DocumentConverter, PdfFormatOption
opts = PdfPipelineOptions(do_ocr=False, generate_picture_images=True, images_scale=2.0)
conv = DocumentConverter(format_options={InputFormat.PDF: PdfFormatOption(pipeline_options=opts)})
doc = conv.convert("report.pdf").document
for i, pic in enumerate(doc.pictures, start=1):
img = pic.get_image(doc)
if img is not None:
img.save(f"figure_{i}.png")
print(i, pic.prov[0].page_no, pic.caption_text(doc)[:70])7 · Convert bytes (S3, an upload, an email attachment)#
from io import BytesIO
from docling.datamodel.base_models import DocumentStream
from docling.document_converter import DocumentConverter
data = open("report.pdf", "rb").read() # e.g. s3.get_object(...)["Body"].read()
doc = DocumentConverter().convert(DocumentStream(name="report.pdf", stream=BytesIO(data))).document
print(doc.name, len(doc.texts))8 · Only the first pages#
from docling.document_converter import DocumentConverter
res = DocumentConverter().convert("report.pdf", page_range=(1, 2))
print(len(res.pages), "pages converted")
print(res.document.export_to_markdown()[:200])9 · Word, PowerPoint and Excel to Markdown#
from docling.document_converter import DocumentConverter
converter = DocumentConverter()
for name in ["memo.docx"]: # .pptx and .xlsx work the same way
md = converter.convert(name).document.export_to_markdown()
print(md)Office files skip the layout and OCR models: our two-paragraph Word file with a table converted in a fraction of a second.
10 · Save once, re-export later without reconverting#
from docling.document_converter import DocumentConverter
from docling_core.types.doc import DoclingDocument
DocumentConverter().convert("report.pdf").document.save_as_json("report.json")
doc = DoclingDocument.load_from_json("report.json") # instant, no models
doc.save_as_html("report.html")
print(doc.export_to_text()[:120])11 · Chunks to JSONL for a vector store#
import json
from docling.chunking import HybridChunker
from docling.document_converter import DocumentConverter
doc = DocumentConverter().convert("report.pdf").document
chunker = HybridChunker(max_tokens=512)
with open("chunks.jsonl", "w") as f:
for i, ch in enumerate(chunker.chunk(doc)):
f.write(json.dumps({
"id": f"report-{i}",
"text": chunker.contextualize(ch),
"headings": ch.meta.headings,
"pages": sorted({p.page_no for it in ch.meta.doc_items for p in it.prov}),
}) + "\n")12 · A web page to Markdown#
from docling.document_converter import DocumentConverter
doc = DocumentConverter().convert("https://en.wikipedia.org/wiki/Optical_character_recognition").document
print(doc.export_to_markdown()[:400])HTML is parsed from the DOM, so it converts quickly with headings, lists and tables intact.
Frequently asked questions
Where are the official Docling examples?
The Docling documentation has an examples section at docling-project.github.io/docling/examples. The recipes here are independent, shorter and each was run on Docling 2.148.0.
Do these recipes work with older Docling versions?
Most do from 2.x, but some APIs used here (the confidence report, docling.chunking imports) are recent. Upgrade to the version shown at the top of the page if something is missing.