Blog

Convertește DOCX în Markdown cu Python

12 august 2026 · 5 min de citit


Dacă lucrezi cu date de antrenare pentru AI, pipeline-uri de documente sau sisteme RAG, aproape sigur ai avut de-a face cu fișiere DOCX. Documentele Word sunt peste tot — ciorne de cercetare, rapoarte de business, contracte juridice, manuscrise — dar sunt dificil de procesat programatic.

Acest articol îți arată cum să convertești DOCX în Markdown curat folosind API-ul REST AnyMD din Python, cu procesare asincronă în lot, gestionarea erorilor și paginare pentru fluxuri de lucru la scară de producție.

De ce Markdown din DOCX?

DOCX este un format binar (un ZIP cu fișiere XML). Biblioteci precum python-docx pot extrage text, dar pierd structura: titlurile devin paragrafe simple, listele se reduc la text indentat, iar tabelele devin zgomot separat prin taburi. Markdown păstrează toate acestea într-un format pe care orice LLM, bază de date vectorială și generator de site-uri statice îl poate consuma nativ.

Conversie dintr-un singur pas

Cel mai simplu caz — un singur fișier DOCX:

import requests

url = "https://anymd.net/api/convert"
headers = {"Authorization": "Bearer your-api-key"}

with open("report.docx", "rb") as f:
    resp = requests.post(url, headers=headers, files={"file": ("report.docx", f)})

if resp.ok:
    markdown = resp.text
    print(f"Got {len(markdown)} chars of Markdown")
else:
    print(f"Error {resp.status_code}: {resp.text}")

AnyMD detectează automat DOCX din extensia fișierului și returnează GitHub-Flavored Markdown. Titlurile, listele numerotate, listele cu marcatori, bold/italic, tabelele, imaginile și hyperlinkurile sunt toate păstrate — exact cum le-ai vedea dacă ai deschide documentul în Word.

Conversie asincronă în lot cu reîncercări

Când ai 50 sau 500 de fișiere DOCX, conversia secvențială este prea lentă. Iată un procesor asincron în lot cu gestionarea corectă a erorilor:

import asyncio
import aiohttp
from pathlib import Path

API_URL = "https://anymd.net/api/convert"
HEADERS = {"Authorization": "Bearer your-api-key"}

async def convert_one(session: aiohttp.ClientSession, path: Path, out_dir: Path) -> str:
    for attempt in range(3):
        try:
            data = aiohttp.FormData()
            data.add_field("file", path.read_bytes(), filename=path.name)
            async with session.post(API_URL, headers=HEADERS, data=data) as resp:
                if resp.status == 429:
                    wait = int(resp.headers.get("Retry-After", 5))
                    await asyncio.sleep(wait)
                    continue
                if resp.ok:
                    md = await resp.text()
                    out_path = out_dir / f"{path.stem}.md"
                    out_path.write_text(md)
                    return f"✓ {path.name}"
                return f"✗ {path.name} ({resp.status})"
        except (aiohttp.ClientError, asyncio.TimeoutError) as e:
            if attempt == 2:
                return f"✗ {path.name} — {e}"
            await asyncio.sleep(1.5 ** attempt)

async def batch_convert(docx_dir: str, out_dir: str, concurrency: int = 10):
    docx_files = list(Path(docx_dir).glob("*.docx"))
    out_path = Path(out_dir)
    out_path.mkdir(exist_ok=True)

    connector = aiohttp.TCPConnector(limit=concurrency)
    async with aiohttp.ClientSession(connector=connector) as session:
        tasks = [convert_one(session, p, out_path) for p in docx_files]
        results = await asyncio.gather(*tasks)

    ok = sum(1 for r in results if r.startswith("✓"))
    print(f"{ok}/{len(results)} converted — see {out_dir}/")

asyncio.run(batch_convert("docx_input", "markdown_output"))

Scriptul folosește un pool de sesiuni cu număr limitat de conexiuni (implicit 10 cereri simultane), reîncearcă la limitări de rată 429 și erori tranzitorii cu backoff exponențial și scrie fiecare rezultat ca un .md fișier.

Paginare pentru biblioteci mari de documente

Dacă preiei documente dintr-un API sau dintr-un bucket S3, este posibil să ai nevoie de procesare paginată. Iată un model cu generator:

import requests
from pathlib import Path
from typing import Generator

def document_batches(doc_dir: str, batch_size: int = 25) -> Generator[list[Path], None, None]:
    files = sorted(Path(doc_dir).glob("*.docx"))
    for i in range(0, len(files), batch_size):
        yield files[i : i + batch_size]

def convert_batch(batch: list[Path], api_key: str) -> list[tuple[str, bool]]:
    results = []
    with requests.Session() as sess:
        sess.headers.update({"Authorization": f"Bearer {api_key}"})
        for path in batch:
            with open(path, "rb") as f:
                resp = sess.post("https://anymd.net/api/convert", files={"file": (path.name, f)})
            if resp.ok:
                out = path.with_suffix(".md")
                out.write_text(resp.text)
                results.append((path.name, True))
            else:
                results.append((path.name, False))
    return results

# Process 10,000 documents in batches
total, ok = 0, 0
for batch in document_batches("archive", batch_size=25):
    results = convert_batch(batch, "your-api-key")
    for name, success in results:
        total += 1
        if success:
            ok += 1
    print(f"Progress: {ok}/{total}")

print(f"Done: {ok}/{total} documents converted")

Gestionarea fișierelor DOCX mari

AnyMD gestionează fișiere DOCX de până la 50 MB în planul plătit.

Ce se păstrează

Caracteristică DOCXOutput Markdown
Titluri 1–6# până la ######
Bold / Italic**bold** / *italic*
Liste numerotate1. item — imbricare corectă
Liste cu marcatori- item — imbricare corectă
TabeleSintaxă de tabel GFM cu aliniere
Hyperlinkuri[text](url)
Imagini![alt](path)
Blocuri de codBlocuri delimitate cu ```
Citate bloc> quote

Comparație cu python-docx

Biblioteca Python standard python-docx îți oferă acces de nivel jos la elementele interne DOCX — paragrafe, run-uri, stiluri. Este puternic pentru generarea programatică de documente, dar pentru extracție înseamnă că trebuie să reimplementezi fiecare regulă structurală aplicată de rendererul Word:

  • Titluri — stilurile de paragraf trebuie mapate manual la titluri Markdown
  • Liste — necesită parsarea elementelor numPr și urmărirea adâncimii listelor
  • Tabele — extragere celulă cu celulă, rând cu rând, cu formatare GFM manuală
  • Imagini — extragerea referințelor rId apoi dezarhivarea fișierelor media
  • Urmărirea modificărilor — fără suport integrat

AnyMD face toate acestea printr-un singur apel API. Un format de învățat, o integrare de întreținut, un serviciu de monitorizat.

# python-docx approach — ~150 lines to get passable Markdown
from docx import Document
import re

doc = Document("report.docx")
output = []
for para in doc.paragraphs:
    if para.style.name.startswith("Heading"):
        level = para.style.name[-1]
        output.append(f"{'#' * int(level)} {para.text}")
    else:
        output.append(para.text)

# Compare: AnyMD — 6 lines, no edge cases
# curl https://anymd.net/api/convert -H "Authorization: Bearer ***" -F "file=@report.docx"

De la DOCX la un pipeline RAG

După ce fișierele DOCX sunt în Markdown, următorul pas este chunking-ul și embedding-ul pentru RAG. Outputul AnyMD este intrarea ideală pentru strategii de chunking semantic — limitele titlurilor, structura listelor și anteturile tabelelor sunt păstrate, astfel încât chunk-urile respectă semantica documentului în loc să taie paragrafele la mijlocul propoziției.

Pentru o comparație mai aprofundată a metodelor de chunking pe output Markdown, consultă ghidul nostru despre chunking recursiv pe caractere.

Prețuri

PlanPagini/lunăDimensiune maximă fișierPreț
Gratuit10010 MB$0
Starter50025 MB$19
Pro5,00050 MB$99
EnterprisePersonalizatPersonalizatPersonalizat

O pagină DOCX obișnuită se convertește în mai puțin de 0,3 secunde.

Obține cheia API gratuită — 100 de pagini/lună, fără card de credit.


← Citește mai mult →