Hvis du arbejder med AI-træningsdata, dokumentpipelines eller RAG-systemer, har du næsten helt sikkert haft med DOCX-filer at gøre. Word-dokumenter er overalt — forskningsudkast, forretningsrapporter, juridiske kontrakter, manuskripter — men de er besværlige at behandle programmatisk.
Dette indlæg viser, hvordan du konverterer DOCX til ren Markdown med AnyMD's REST API fra Python, med asynkron batchbehandling, fejlhåndtering og paginering til workflows i produktionsskala.
Hvorfor Markdown fra DOCX?
DOCX er et binært format (en ZIP med XML-filer). Biblioteker som python-docx kan udtrække tekst, men de mister strukturen: overskrifter bliver til almindelige afsnit, lister kollapser til indrykket tekst, og tabeller bliver til tabulatorsepareret støj. Markdown bevarer det hele i et format, som enhver LLM, vektordatabase og statisk sitegenerator kan bruge direkte.
Engangskonvertering
Det enkleste tilfælde — én DOCX-fil:
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 registrerer automatisk DOCX ud fra filtypen og returnerer GitHub-Flavored Markdown. Overskrifter, nummererede lister, punktlister, fed/kursiv, tabeller, billeder og hyperlinks bevares alle — præcis som du ville se dem, hvis du åbnede dokumentet i Word.
Asynkron batchkonvertering med genforsøg
Når du har 50 eller 500 DOCX-filer, er sekventiel konvertering for langsom. Her er en asynkron batchprocessor med korrekt fejlhåndtering:
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"))
Scriptet bruger en session-pool med forbindelsesbegrænsning (10 samtidige forespørgsler som standard), forsøger igen ved 429-rate limits og midlertidige fejl med eksponentiel backoff og skriver hvert resultat som en .md fil.
Paginering til store dokumentbiblioteker
Hvis du henter dokumenter fra et API eller en S3-bucket, kan du have brug for pagineret behandling. Her er et generator-mønster:
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")
Håndtering af store DOCX-filer
AnyMD håndterer DOCX-filer på op til 50 MB på den betalte plan.
Hvad der bevares
| DOCX-funktion | Markdown-output |
|---|---|
| Overskrift 1–6 | # til ###### |
| Fed / Kursiv | **bold** / *italic* |
| Nummererede lister | 1. item — korrekt indlejring |
| Punktlister | - item — korrekt indlejring |
| Tabeller | GFM-tabelsyntaks med justering |
| Hyperlinks | [text](url) |
| Billeder |  |
| Kodeblokke | Blokke afgrænset med ``` |
| Blokcitater | > quote |
Sammenligning med python-docx
Standardbiblioteket i Python python-docx giver dig adgang på lavt niveau til DOCX' interne struktur — afsnit, runs og typografier. Det er effektivt til programmatisk dokumentgenerering, men ved udtrækning betyder det, at du selv skal genimplementere hver strukturel regel, som Words renderer anvender:
- Overskrifter — afsnitstypografier skal manuelt mappes til Markdown-overskrifter
- Lister — kræver parsing af
numPr-elementer og sporing af listeniveau - Tabeller — udtrækning celle for celle og række for række med manuel GFM-formatering
- Billeder — udtrækning af
rId-referencer og derefter udpakning af mediefiler - Registrer ændringer — ingen indbygget understøttelse
AnyMD gør alt dette i ét API-kald. Ét format at lære, én integration at vedligeholde, én tjeneste at overvåge.
# 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"
Fra DOCX til en RAG-pipeline
Når dine DOCX-filer er Markdown, er næste trin chunking og embedding til RAG. AnyMD-output er det ideelle input til semantiske chunking-strategier — grænser ved overskrifter, listestruktur og tabeloverskrifter bevares, så dine chunks respekterer dokumentets semantik i stedet for at skære afsnit over midt i en sætning.
Se en dybere sammenligning af chunking-metoder til Markdown-output i vores guide til rekursiv character chunking.
Priser
| Plan | Sider/måned | Maksimal filstørrelse | Pris |
|---|---|---|---|
| Gratis | 100 | 10 MB | $0 |
| Starter | 500 | 25 MB | $19 |
| Pro | 5,000 | 50 MB | $99 |
| Enterprise | Tilpasset | Tilpasset | Tilpasset |
En typisk DOCX-side konverteres på under 0,3 sekund.
Få din gratis API-nøgle — 100 sider/måned, intet kreditkort påkrævet.