파이썬으로 HTML을 Markdown으로 변환하는 방법: 포괄적인 가이드
HTML을 깨끗하고 LLM에 적합한 Markdown으로 변환하는 Python
HTML을 Markdown으로 변환은 웹 콘텐츠를 대규모 언어 모델(LLM), 문서 시스템, 또는 Hugo와 같은 정적 사이트 생성기로 준비하는 현대 개발 워크플로우에서 근본적인 작업입니다. 이 가이드는 우리의 2026년 문서 도구: Markdown, LaTeX, PDF 및 인쇄 워크플로우 허브의 일부입니다.
HTML은 웹 브라우저를 위한 풍부한 스타일링과 구조를 제공하도록 설계되어 있지만, Markdown은 텍스트 처리, 버전 관리 및 AI 소비에 이상적인 깔끔하고 읽기 쉬운 형식을 제공합니다. Markdown 구문에 익숙하지 않다면, Markdown 체크리스트를 참고하여 포괄적인 참조 자료를 확인해 보세요.

이 포괄적인 검토에서 우리는 HTML-to-Markdown 변환을 위한 6가지 Python 패키지를 탐구할 것이며, 실용적인 코드 예제, 성능 벤치마크, 실제 사용 사례를 제공할 것입니다. LLM 훈련 파이프라인을 구축하거나 블로그를 Hugo로 이전하거나 문서를 스크레이핑하는 경우에도 워크플로우에 적합한 도구를 찾을 수 있을 것입니다.
대안적인 접근법: 더 정교한 콘텐츠 추출과 의미 이해가 필요한 경우, LLM과 Ollama를 사용하여 HTML을 Markdown으로 변환을 고려해 보세요. 이 방법은 복잡한 레이아웃에 대한 AI 기반 변환을 제공합니다.
학습할 내용:
- 6가지 라이브러리의 상세 비교(각각의 장단점 포함)
- 실제 웹 HTML 샘플을 사용한 성능 벤치마크
- 일반적인 사용 사례에 대한 프로덕션 준비된 코드 예제
- LLM 전처리 워크플로우에 대한 최선의 실천 방법
- 요구사항에 따라 특정 추천 사항
LLM 전처리에 Markdown을 사용하는 이유
도구에 빠져들기 전에, Markdown이 LLM 워크플로우에서 특히 유용한 이유를 이해해 보세요:
- 토큰 효율성: 동일한 콘텐츠에 대해 Markdown은 HTML보다 훨씬 적은 토큰을 사용합니다.
- 의미적 명확성: Markdown은 복잡한 태그 없이 문서 구조를 유지합니다.
- 가독성: 인간과 LLM 모두가 Markdown 구문을 쉽게 파싱할 수 있습니다.
- 일관성: 표준화된 형식은 모델 입력의 모호성을 줄입니다.
- 저장 공간: 훈련 데이터 및 컨텍스트 창의 파일 크기가 작아집니다.
Markdown의 유연성은 HTML 변환을 넘어선 것으로, 문서 워크플로우에서 워드 문서를 Markdown으로 변환를 할 수 있고, 개인 지식 관리 시스템인 Obsidian을 사용한 개인 지식 관리에 사용할 수 있습니다. 문서 변환과 Markdown, LaTeX, PDF 간 포맷팅에 대한 더 많은 내용은 문서 도구 허브에서 확인해 보세요.
TL;DR - 빠른 비교 매트릭스
시간이 부족한 경우, 6가지 라이브러리의 포괄적인 비교를 한눈에 보세요. 이 표는 귀하의 특정 요구사항에 맞는 도구를 빠르게 식별하는 데 도움이 될 것입니다:
| 기능 | html2text | markdownify | html-to-markdown | trafilatura | domscribe | html2md |
|---|---|---|---|---|---|---|
| HTML5 지원 | 부분적 | 부분적 | 전체 | 전체 | 전체 | 전체 |
| 타입 힌트 | 없음 | 없음 | 있음 | 부분적 | 없음 | 부분적 |
| 커스텀 핸들러 | 제한적 | 우수 | 양호 | 제한적 | 양호 | 제한적 |
| 테이블 지원 | 기본 | 기본 | 고급 | 양호 | 양호 | 양호 |
| 비동기 지원 | 없음 | 없음 | 없음 | 없음 | 없음 | 있음 |
| 콘텐츠 추출 | 없음 | 없음 | 없음 | 우수 | 없음 | 양호 |
| 메타데이터 추출 | 없음 | 없음 | 있음 | 우수 | 없음 | 있음 |
| CLI 도구 | 없음 | 없음 | 있음 | 있음 | 없음 | 있음 |
| 속도 | 중간 | 느림 | 빠름 | 매우 빠름 | 중간 | 매우 빠름 |
| 활발한 개발 | 없음 | 있음 | 있음 | 있음 | 제한적 | 있음 |
| 파이썬 버전 | 3.6+ | 3.7+ | 3.9+ | 3.6+ | 3.8+ | 3.10+ |
| 의존성 | 없음 | BS4 | lxml | lxml | BS4 | aiohttp |
빠른 선택 가이드:
- 속도가 필요하다면? → trafilatura 또는 html2md
- 커스터마이징이 필요하다면? → markdownify
- 타입 안전성이 필요하다면? → html-to-markdown
- 간단한 사용이 필요하다면? → html2text
- 콘텐츠 추출이 필요하다면? → trafilatura
경쟁자들: 6가지 Python 패키지 비교
각 라이브러리에 실용적인 코드 예제, 구성 옵션, 실제 인사이트를 깊이 있게 탐구해 보겠습니다. 각 섹션에는 설치 지침, 사용 패턴, 강점과 한계에 대한 솔직한 평가가 포함됩니다.
1. html2text - 전통적인 선택
Aaron Swartz가 개발한 html2text는 10년 이상 Python 생태계에서 핵심 도구로 사용되어 왔습니다. 이 도구는 깔끔하고 가독성이 높은 Markdown 출력을 생성하는 데 초점을 맞추고 있습니다.
설치:
pip install html2text
기본 사용법:
import html2text
# 컨버터 인스턴스 생성
h = html2text.HTML2Text()
# 옵션 설정
h.ignore_links = False
h.ignore_images = False
h.ignore_emphasis = False
h.body_width = 0 # 줄 바꿈 없음
html_content = """
<h1>웹 크롤링에 오신 것을 환영합니다</h1>
<p>이것은 <strong>포괄적인 가이드</strong>입니다.</p>
<ul>
<li>사용이 간단함</li>
<li>검증된 기술</li>
<li>광범위하게 채택됨</li>
</ul>
<a href="https://example.com">더 알아보기</a>
"""
markdown = h.handle(html_content)
print(markdown)
출력:
# 웹 크롤링에 오신 것을 환영합니다
이것은 **포괄적인 가이드**입니다.
* 사용이 간단함
* 검증된 기술
* 광범위하게 채택됨
[더 알아보기](https://example.com)
고급 설정:
import html2text
h = html2text.HTML2Text()
# 특정 요소 건너뛰기
h.ignore_links = True
h.ignore_images = True
# 포맷팅 제어
h.body_width = 80 # 80자에서 줄 바꿈
h.unicode_snob = True # 유니코드 문자 사용
h.emphasis_mark = '*' # 강조에 * 사용
h.strong_mark = '**'
# 테이블 처리
h.ignore_tables = False
# 미리 정의된 텍스트 보호
h.protect_links = True
장점:
- 오랜 기간 사용되어 오래된 기술(15년 이상 개발)
- 광범위한 설정 옵션
- 테두리 사항 잘 처리
- 외부 의존성 없음
단점:
- 제한적인 HTML5 지원
- 일관되지 않은 간격 생성 가능
- 활발한 유지보수가 없음(2020년 이후 주요 업데이트 없음)
- 단일 스레드 처리만 지원
최적의 사용 사례: 간단한 HTML 문서, 오래된 시스템, 안정성이 우선시되는 경우
2. markdownify - 유연한 선택
markdownify는 BeautifulSoup4를 활용하여 유연한 HTML 파싱과 맞춤형 태그 처리를 제공합니다.
설치:
pip install markdownify
기본 사용법:
from markdownify import markdownify as md
html = """
<article>
<h2>현대 웹 개발</h2>
<p>Python과 <code>모던 프레임워크</code>를 사용하여 구축합니다.</p>
<blockquote>
<p>단순함이 최고의 세련됨입니다.</p>
</blockquote>
</article>
"""
markdown = md(html)
print(markdown)
출력:
## 현대 웹 개발
Python과 `모던 프레임워크`를 사용하여 구축합니다.
> 단순함이 최고의 세련됨입니다.
고급 사용법 및 맞춤형 핸들러:
from markdownify import MarkdownConverter
class CustomConverter(MarkdownConverter):
"""
특정 태그 처리를 위한 맞춤형 컨버터 생성
"""
def convert_img(self, el, text, convert_as_inline):
"""대체 텍스트를 포함한 맞춤형 이미지 핸들러"""
alt = el.get('alt', '')
src = el.get('src', '')
title = el.get('title', '')
if title:
return f''
return f''
def convert_pre(self, el, text, convert_as_inline):
"""언어 감지와 함께 강화된 코드 블록 처리"""
code = el.find('code')
if code:
# 클래스 속성에서 언어 추출 (예: 'language-python')
classes = code.get('class', [''])
language = classes[0].replace('language-', '') if classes else ''
return f'\n```{language}\n{code.get_text()}\n```\n'
return f'\n```\n{text}\n```\n'
# 맞춤형 컨버터 사용
html = '<pre><code class="language-python">def hello():\n print("world")</code></pre>'
markdown = CustomConverter().convert(html)
print(markdown)
Markdown 코드 블록과 구문 강조에 대한 자세한 내용은 우리의 Markdown 코드 블록 사용법을 참조하세요.
선택적 태그 변환:
from markdownify import markdownify as md
# 특정 태그 전체 제거
markdown = md(html, strip=['script', 'style', 'nav'])
# 특정 태그만 변환
markdown = md(
html,
heading_style="ATX", # 헤딩에 # 사용
bullets="-", # 목록에 - 사용
strong_em_symbol="*", # 강조에 * 사용
)
장점:
- BeautifulSoup4 기반(강력한 HTML 파싱)
- 서브클래싱을 통한 매우 유연한 커스터마이징
- 활발한 유지보수
- 좋은 문서화
단점:
- BeautifulSoup4 의존성 필요
- 대규모 문서 처리 시 느림
- 기본 제공 테이블 지원 제한
최적의 사용 사례: 맞춤형 변환 로직, BeautifulSoup4를 이미 사용하는 프로젝트
3. html-to-markdown - 현대적인 강력한 도구
html-to-markdown은 완전히 타입 안전한, 현대적인 라이브러리로, 포괄적인 HTML5 지원과 광범위한 설정 옵션을 제공합니다.
설치:
pip install html-to-markdown
기본 사용법:
from html_to_markdown import convert
html = """
<article>
<h1>기술 문서</h1>
<table>
<thead>
<tr>
<th>기능</th>
<th>지원</th>
</tr>
</thead>
<tbody>
<tr>
<td>HTML5</td>
<td>✓</td>
</tr>
<tr>
<td>테이블</td>
<td>✓</td>
</tr>
</tbody>
</table>
</article>
"""
markdown = convert(html)
print(markdown)
고급 설정:
from html_to_markdown import convert, Options
# 커스텀 옵션 생성
options = Options(
heading_style="ATX",
bullet_style="-",
code_language_default="python",
strip_tags=["script", "style"],
escape_special_chars=True,
table_style="pipe", # 테이블에 | 사용
preserve_whitespace=False,
extract_metadata=True, # 메타 태그 추출
)
markdown = convert(html, options=options)
명령줄 인터페이스:
# 단일 파일 변환
html-to-markdown input.html -o output.md
# 옵션과 함께 변환
html-to-markdown input.html \
--heading-style atx \
--strip-tags script,style \
--extract-metadata
# 배치 변환
find ./html_files -name "*.html" -exec html-to-markdown {} -o ./markdown_files/{}.md \;
장점:
- HTML5 지원(포함 semantic 요소)
- 포괄적인 타입 힌트를 갖춘 타입 안전
- 테이블 처리 강화(병합된 셀, 정렬)
- 메타데이터 추출 기능
- 활발한 개발 및 현대적인 코드베이스
단점:
- Python 3.9+ 필요
- 더 큰 의존성 범위
- 학습 곡선이 가파름
최적의 사용 사례: 복잡한 HTML5 문서, 타입 안전 프로젝트, 프로덕션 시스템
4. trafilatura - 콘텐츠 추출 전문가
trafilatura는 단순한 HTML-to-Markdown 변환기 이상의 존재입니다. 웹 크롤링 및 기사 추출을 위해 특별히 설계된 지능형 콘텐츠 추출 라이브러리입니다.
설치:
pip install trafilatura
기본 사용법:
import trafilatura
# URL에서 다운로드 및 추출
url = "https://example.com/article"
downloaded = trafilatura.fetch_url(url)
markdown = trafilatura.extract(downloaded, output_format='markdown')
print(markdown)
참고: Trafilatura는 내장 URL 다운로드 기능을 포함하지만, API 또는 인증된 엔드포인트를 사용할 때 더 복잡한 HTTP 작업이 필요한 경우, cURL 체크리스트가 도움이 될 수 있습니다.
고급 콘텐츠 추출:
import trafilatura
from trafilatura.settings import use_config
# 커스텀 설정 생성
config = use_config()
config.set("DEFAULT", "EXTRACTION_TIMEOUT", "30")
html = """
<html>
<head><title>기사 제목</title></head>
<body>
<nav>네비게이션 메뉴</nav>
<article>
<h1>주요 기사</h1>
<p>중요한 콘텐츠가 여기 있습니다.</p>
</article>
<aside>광고</aside>
<footer>푸터 콘텐츠</footer>
</body>
</html>
"""
# 주요 콘텐츠만 추출
markdown = trafilatura.extract(
html,
output_format='markdown',
include_comments=False,
include_tables=True,
include_images=True,
include_links=True,
config=config
)
# 메타데이터와 함께 추출
result = trafilatura.extract(
html,
output_format='markdown',
with_metadata=True
)
if result:
print(f"제목: {result.get('title', 'N/A')}")
print(f"작성자: {result.get('author', 'N/A')}")
print(f"날짜: {result.get('date', 'N/A')}")
print(f"\n콘텐츠:\n{result.get('text', '')}")
배치 처리:
import trafilatura
from concurrent.futures import ThreadPoolExecutor
from pathlib import Path
def process_url(url):
"""URL에서 마크다운 추출"""
downloaded = trafilatura.fetch_url(url)
if downloaded:
return trafilatura.extract(
downloaded,
output_format='markdown',
include_links=True,
include_images=True
)
return None
# 여러 URL 병렬 처리
urls = [
"https://example.com/article1",
"https://example.com/article2",
"https://example.com/article3",
]
with ThreadPoolExecutor(max_workers=5) as executor:
results = list(executor.map(process_url, urls))
for i, markdown in enumerate(results):
if markdown:
Path(f"article_{i}.md").write_text(markdown, encoding='utf-8')
장점:
- 지능형 콘텐츠 추출(불필요한 부분 제거)
- 내장 URL 다운로드 기능 및 강력한 오류 처리
- 메타데이터 추출(제목, 작성자, 날짜)
- 언어 감지
- 뉴스 기사 및 블로그 게시물에 최적화
- C 기반의 최적화된 파싱
단점:
- 일반 HTML에서 너무 많은 콘텐츠 제거 가능성
- 기사 추출에 초점(일반용이 아님)
- 테두리 사항에 대한 구성 복잡성
최적의 사용 사례: 웹 크롤링, 기사 추출, LLM 훈련 데이터 준비
5. domscribe - 의미 보존 전문가
domscribe는 HTML의 의미를 보존하면서 Markdown으로 변환하는 데 초점을 맞추고 있습니다.
설치:
pip install domscribe
기본 사용법:
from domscribe import html_to_markdown
html = """
<article>
<header>
<h1>세미안틱 HTML 이해</h1>
<time datetime="2024-10-24">2024년 10월 24일</time>
</header>
<section>
<h2>서론</h2>
<p>세미안틱 HTML은 <mark>의미</mark>를 제공합니다.</p>
</section>
<aside>
<h3>관련 주제</h3>
<ul>
<li>접근성</li>
<li>SEO</li>
</ul>
</aside>
</article>
"""
markdown = html_to_markdown(html)
print(markdown)
커스텀 옵션:
from domscribe import html_to_markdown, MarkdownOptions
options = MarkdownOptions(
preserve_semantic_structure=True,
include_aria_labels=True,
strip_empty_elements=True
)
markdown = html_to_markdown(html, options=options)
장점:
- 세미안틱 HTML5 구조 보존
- 현대 웹 구성 요소 잘 처리
- 깔끔한 API 설계
단점:
- 초기 개발 단계(API가 변경될 수 있음)
- 성숙한 대안보다 문서화가 제한적
- 커뮤니티와 예제가 적음
최적의 사용 사례: 세미안틱 HTML5 문서, 접근성 중심 프로젝트, HTML5 세미안틱 구조 보존이 필수적인 경우
참고: domscribe는 다른 도구보다 테스트가 덜 되었지만, 세미안틱 HTML 보존이라는 특정 니치를 충족합니다.
6. html2md - 비동기 강력한 도구
html2md는 고성능 배치 변환을 위해 비동기 처리를 설계되었습니다.
설치:
pip install html2md
명령줄 사용법:
# 전체 디렉토리 변환
m1f-html2md convert ./website -o ./docs
# 커스텀 설정으로 변환
m1f-html2md convert ./website -o ./docs \
--remove-tags nav,footer \
--heading-offset 1 \
--detect-language
# 단일 파일 변환
m1f-html2md convert index.html -o readme.md
프로그래밍적 사용법:
import asyncio
from html2md import convert_html
async def convert_files():
"""비동기 배치 변환"""
html_files = [
'page1.html',
'page2.html',
'page3.html'
]
tasks = [convert_html(file) for file in html_files]
results = await asyncio.gather(*tasks)
return results
# 변환 실행
results = asyncio.run(convert_files())
장점:
- 비동기 처리로 고성능
- 지능형 콘텐츠 선택자 감지
- YAML 프론트메타 생성(허구에 최적)
- 코드 언어 감지
- 병렬 처리 지원
단점:
- Python 3.10+ 필요
- CLI 중심(유연한 API가 아님)
- 문서화가 더 체계적일 수 있음
최적의 사용 사례: 대규모 이전, 배치 변환, 허구/Jekyll 이전
성능 벤치마킹
성능은 특히 수천 개의 문서를 LLM 훈련 또는 대규모 이전에 사용할 때 중요합니다. 라이브러리 간의 속도 차이를 이해하면 워크플로우에 대한 인사이트를 얻을 수 있습니다.
비교 성능 분석:
일반적인 사용 패턴에 기반하여, 다음의 세 가지 실제 시나리오에서 이 라이브러리들이 어떻게 비교되는지 보여줍니다:
- 간단한 HTML: 텍스트, 헤딩, 링크가 있는 기본 블로그 게시물(5KB)
- 복잡한 HTML: 중첩된 테이블과 코드 블록이 있는 기술 문서(50KB)
- 실제 웹사이트: 네비게이션, 푸터, 사이드바, 광고가 포함된 전체 웹페이지(200KB)
다음은 이 라이브러리들을 직접 테스트할 수 있는 예시 벤치마크 코드입니다:
import time
import html2text
from markdownify import markdownify
from html_to_markdown import convert
import trafilatura
def benchmark(html_content, iterations=100):
"""변환 속도 벤치마킹"""
# html2text
start = time.time()
h = html2text.HTML2Text()
for _ in range(iterations):
_ = h.handle(html_content)
html2text_time = time.time() - start
# markdownify
start = time.time()
for _ in range(iterations):
_ = markdownify(html_content)
markdownify_time = time.time() - start
# html-to-markdown
start = time.time()
for _ in range(iterations):
_ = convert(html_content)
html_to_markdown_time = time.time() - start
# trafilatura
start = time.time()
for _ in range(iterations):
_ = trafilatura.extract(html_content, output_format='markdown')
trafilatura_time = time.time() - start
return {
'html2text': html2text_time,
'markdownify': markdownify_time,
'html-to-markdown': html_to_markdown_time,
'trafilatura': trafilatura_time
}
일반적인 성능 특성 (대표적인 상대 속도):
| 패키지 | 간단한 (5KB) | 복잡한 (50KB) | 실제 사이트 (200KB) |
|---|---|---|---|
| html2text | 중간 | 느림 | 느림 |
| markdownify | 느림 | 느림 | 가장 느림 |
| html-to-markdown | 빠름 | 빠름 | 빠름 |
| trafilatura | 빠름 | 매우 빠름 | 매우 빠름 |
| html2md (비동기) | 매우 빠름 | 매우 빠름 | 가장 빠름 |
핵심 관찰:
html2md와trafilatura는 복잡한 문서에 가장 빠르며, 배치 처리에 이상적입니다.html-to-markdown은 속도와 기능 면에서 생산성 사용에 가장 적합합니다.markdownify는 느리지만 가장 유연하며, 커스텀 핸들러가 필요한 경우 교환 가치가 있습니다.html2text는 나이가 많아 속도가 느리지만, 간단한 사용 사례에 안정적입니다.
참고: 파일 수가 수백 또는 수천 개가 되어야 속도 차이가 중요해집니다. 간헐적인 변환에 대해서는 어떤 라이브러리도 충분히 작동합니다. 기능과 커스터마이징 옵션에 집중하세요.
실제 사용 사례
이론은 도움이 되지만, 이러한 도구들이 실제 생산 환경에서 어떻게 작동하는지 보여주는 실용적인 예시가 중요합니다. 다음은 네 가지 일반적인 시나리오와 실제 사용 가능한 코드가 포함된 것입니다.
사용 사례 1: LLM 훈련 데이터 준비
요구사항: 수천 개의 문서 페이지에서 깨끗한 텍스트 추출
추천: trafilatura + 병렬 처리
import trafilatura
from pathlib import Path
from concurrent.futures import ProcessPoolExecutor
def process_html_file(html_path):
"""HTML 파일을 마크다운으로 변환"""
html = Path(html_path).read_text(encoding='utf-8')
markdown = trafilatura.extract(
html,
output_format='markdown',
include_links=False, # 훈련 데이터에 더 깨끗한 데이터를 위해 제거
include_images=False,
include_comments=False
)
if markdown:
output_path = html_path.replace('.html', '.md')
Path(output_path).write_text(markdown, encoding='utf-8')
return len(markdown)
return 0
# 10,000개의 파일 병렬 처리
html_files = list(Path('./docs').rglob('*.html'))
with ProcessPoolExecutor(max_workers=8) as executor:
token_counts = list(executor.map(process_html_file, html_files))
print(f"처리된 파일 수: {len(html_files)}")
print(f"총 문자 수: {sum(token_counts):,}")
사용 사례 2: 허구 블로그 이전
요구사항: WordPress 블로그를 허구로 이전하면서 프론트메타 추가
추천: html2md CLI
허구는 인기 있는 정적 사이트 생성기로, Markdown을 콘텐츠로 사용합니다. 허구에 대한 더 많은 팁은 우리의 허구 체크리스트를 참조하세요. 그리고 허구 웹사이트에 구조화된 데이터 마크업 추가를 통해 더 나은 SEO를 학습하세요. 우리의 문서 도구 허브에는 Markdown 워크플로우 및 문서 변환에 대한 더 많은 가이드가 있습니다.
# 프론트메타 생성과 함께 모든 게시물 변환
m1f-html2md convert ./wordpress-export \
-o ./hugo/content/posts \
--generate-frontmatter \
--heading-offset 0 \
--remove-tags script,style,nav,footer
또는 프로그래밍적으로:
from html_to_markdown import convert, Options
from pathlib import Path
import yaml
def migrate_post(html_file):
"""WordPress HTML을 허구 마크다운으로 변환"""
html = Path(html_file).read_text()
# 제목 및 날짜 추출
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'html.parser')
title = soup.find('h1').get_text() if soup.find('h1') else '제목 없음'
# 마크다운으로 변환
options = Options(strip_tags=['script', 'style', 'nav', 'footer'])
markdown = convert(html, options=options)
# 허구 프론트메타 추가
frontmatter = {
'title': title,
'date': '2024-10-24',
'draft': False,
'tags': []
}
output = f"---\n{yaml.dump(frontmatter)}---\n\n{markdown}"
# 저장
output_file = html_file.replace('.html', '.md')
Path(output_file).write_text(output, encoding='utf-8')
# 모든 게시물 처리
for html_file in Path('./wordpress-export').glob('*.html'):
migrate_post(html_file)
사용 사례 3: 커스텀 포맷팅을 위한 문서 스크레이퍼
요구사항: 기술 문서를 스크레이핑하고 커스텀 코드 블록 처리
추천: markdownify와 커스텀 컨버터
이 접근법은 위키 시스템에서 문서를 이전하는 데 특히 유용합니다. 문서를 관리하는 경우, 자체 호스팅 위키 및 대안에 관심이 있을 수 있습니다.
from markdownify import MarkdownConverter
import requests
class DocsConverter(MarkdownConverter):
"""기술 문서를 위한 커스텀 컨버터"""
def convert_pre(self, el, text, convert_as_inline):
"""구문 강조와 함께 강화된 코드 블록"""
code = el.find('code')
if code:
# 클래스에서 언어 추출
classes = code.get('class', [])
language = next(
(c.replace('language-', '') for c in classes if c.startswith('language-')),
'text'
)
return f'\n```{language}\n{code.get_text()}\n```\n'
return super().convert_pre(el, text, convert_as_inline)
def convert_div(self, el, text, convert_as_inline):
"""특수 문서 블록 처리"""
classes = el.get('class', [])
# 경고 블록
if 'warning' in classes:
return f'\n> ⚠️ **경고**: {text}\n'
# 정보 블록
if 'info' in classes or 'note' in classes:
return f'\n> 💡 **참고**: {text}\n'
return text
def scrape_docs(url):
"""문서 페이지 스크레이핑 및 변환"""
response = requests.get(url)
markdown = DocsConverter().convert(response.text)
return markdown
# 사용
docs_url = "https://docs.example.com/api-reference"
markdown = scrape_docs(docs_url)
Path('api-reference.md').write_text(markdown)
사용 사례 4: 뉴스레터를 마크다운 아카이브로 변환
요구사항: HTML 이메일 뉴스레터를 가독성이 높은 마크다운으로 변환
추천: 특정 설정으로 html2text 사용
import html2text
import email
from pathlib import Path
def convert_newsletter(email_file):
"""HTML 이메일을 마크다운으로 변환"""
# 이메일 파싱
with open(email_file, 'r') as f:
msg = email.message_from_file(f)
# HTML 부분 추출
html_content = None
for part in msg.walk():
if part.get_content_type() == 'text/html':
html_content = part.get_payload(decode=True).decode('utf-8')
break
if not html_content:
return None
# 컨버터 설정
h = html2text.HTML2Text()
h.ignore_images = False
h.images_to_alt = True
h.body_width = 0
h.protect_links = True
h.unicode_snob = True
# 변환
markdown = h.handle(html_content)
# 메타데이터 추가
subject = msg.get('Subject', '제목 없음')
date = msg.get('Date', '')
output = f"# {subject}\n\n*날짜: {date}*\n\n---\n\n{markdown}"
return output
# 뉴스레터 아카이브 처리
for email_file in Path('./newsletters').glob('*.eml'):
markdown = convert_newsletter(email_file)
if markdown:
output_file = email_file.with_suffix('.md')
output_file.write_text(markdown, encoding='utf-8')
시나리오별 추천
아직도 어떤 라이브러리를 선택해야 할지 확신이 없나요? 구체적인 사용 사례에 따라 가이드를 제공합니다.
웹 크롤링 및 LLM 전처리용
우승자: trafilatura
Trafilatura는 깨끗한 콘텐츠 추출을 위해 불필요한 부분을 제거하는 데 탁월합니다. 다음과 같은 경우에 이상적입니다:
- LLM 훈련 데이터 생성
- 콘텐츠 집계
- 연구 논문 수집
- 뉴스 기사 추출
허구/Jekyll 이전용
우승자: html2md
비동기 처리와 프론트메타 생성으로 대량 이전이 빠르고 간단합니다:
- 배치 변환
- 자동 메타데이터 추출
- YAML 프론트메타 생성
- 헤딩 수준 조정
커스텀 변환 로직용
우승자: markdownify
컨버터를 서브클래싱하여 완전한 제어를 제공합니다:
- 커스텀 태그 핸들러
- 도메인 특화 변환
- 특수 포맷팅 요구사항
- 기존 BeautifulSoup 코드 통합
타입 안전한 프로덕션 시스템용
우승자: html-to-markdown
현대적인, 타입 안전한, 기능이 완비된 라이브러리입니다:
- 완전한 HTML5 지원
- 포괄적인 타입 힌트
- 고급 테이블 처리
- 활발한 유지보수
간단하고 안정적인 변환용
우승자: html2text
“단순히 작동하는” 것이 필요한 경우:
- 외부 의존성 없음
- 검증된 기술
- 광범위한 설정
- 넓은 플랫폼 지원
LLM 전처리를 위한 최고의 실천 방법
사용하는 라이브러리에 관계없이 다음 최고의 실천 방법을 따르면 LLM이 소비하기에 최적화된 높은 품질의 Markdown 출력을 보장할 수 있습니다. 수백만 개의 문서를 처리하는 실제 작업 흐름에서 이 패턴들이 필수적이었습니다.
1. 변환 전에 정리하기
변환 전에 원치 않는 요소를 제거하여 더 깨끗한 출력과 더 나은 성능을 얻으세요:
from bs4 import BeautifulSoup
import trafilatura
def clean_and_convert(html):
"""변환 전에 원치 않는 요소 제거"""
soup = BeautifulSoup(html, 'html.parser')
# 원치 않는 요소 제거
for element in soup(['script', 'style', 'nav', 'footer', 'header', 'aside']):
element.decompose()
# 광고 및 추적 요소 제거
for element in soup.find_all(class_=['ad', 'advertisement', 'tracking']):
element.decompose()
# 정리된 HTML 변환
markdown = trafilatura.extract(
str(soup),
output_format='markdown'
)
return markdown
2. 공백 정규화
다른 변환기들은 공백을 다르게 처리합니다. 문서 집합 전체에서 일관성을 유지하기 위해 출력을 정규화하세요:
import re
def normalize_markdown(markdown):
"""Markdown 공백 정리"""
# 여러 줄 간 공백 제거
markdown = re.sub(r'\n{3,}', '\n\n', markdown)
# 줄 끝 공백 제거
markdown = '\n'.join(line.rstrip() for line in markdown.split('\n'))
# 마지막 줄에 단일 줄바꿈 보장
markdown = markdown.rstrip() + '\n'
return markdown
3. 출력 검증
품질 관리가 필수적입니다. 변환 오류를 조기에 포착하기 위해 검증을 구현하세요:
def validate_markdown(markdown):
"""Markdown 품질 검증"""
issues = []
# HTML 잔여물 검사
if '<' in markdown and '>' in markdown:
issues.append("HTML 태그 발견됨")
# 손상된 링크 검사
if '[' in markdown and ']()' in markdown:
issues.append("빈 링크 발견됨")
# 과도한 코드 블록 검사
code_block_count = markdown.count('```')
if code_block_count % 2 != 0:
issues.append("닫히지 않은 코드 블록 발견됨")
return len(issues) == 0, issues
4. 배치 처리 템플릿
대규모 문서 컬렉션을 처리할 때는 오류 처리, 로깅, 병렬 처리가 포함된 이 생산성 템플릿을 사용하세요:
from pathlib import Path
from concurrent.futures import ProcessPoolExecutor
import trafilatura
import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
def process_file(html_path):
"""단일 HTML 파일 처리"""
try:
html = Path(html_path).read_text(encoding='utf-8')
markdown = trafilatura.extract(
html,
output_format='markdown',
include_links=True,
include_images=False
)
if markdown:
# 정규화
markdown = normalize_markdown(markdown)
# 검증
is_valid, issues = validate_markdown(markdown)
if not is_valid:
logger.warning(f"{html_path}: {', '.join(issues)}")
# 저장
output_path = Path(str(html_path).replace('.html', '.md'))
output_path.write_text(markdown, encoding='utf-8')
return True
return False
except Exception as e:
logger.error(f"{html_path} 처리 중 오류 발생: {e}")
return False
def batch_convert(input_dir, max_workers=4):
"""디렉토리 내 모든 HTML 파일 변환"""
html_files = list(Path(input_dir).rglob('*.html'))
logger.info(f"{len(html_files)}개의 HTML 파일 발견됨")
with ProcessPoolExecutor(max_workers=max_workers) as executor:
results = list(executor.map(process_file, html_files))
success_count = sum(results)
logger.info(f"{success_count}/{len(html_files)}개의 파일 성공적으로 변환됨")
# 사용법
batch_convert('./html_docs', max_workers=8)
결론
Python 생태계는 다양한 시나리오에 최적화된 성숙하고 생산성 있는 HTML-to-Markdown 변환 도구를 제공합니다. 선택은 당신의 구체적인 요구사항과 맞춰야 합니다:
- 빠른 변환:
html2text를 사용하세요. 단순성과 제로 의존성을 갖추고 있습니다. - 커스텀 로직:
markdownify를 사용하세요. 서브클래싱을 통해 최대의 유연성을 제공합니다. - 웹 스크래핑:
trafilatura를 사용하세요. 불필요한 요소 제거와 함께 지능적인 콘텐츠 추출이 가능합니다. - 대규모 이전:
html2md를 사용하세요. 대규모 프로젝트에서 비동기 성능을 제공합니다. - 생산 시스템:
html-to-markdown을 사용하세요. 타입 안전성과 포괄적인 HTML5 지원이 가능합니다. - 의미 보존:
domscribe를 사용하세요. HTML5 의미 구조를 유지할 수 있습니다.
LLM 워크플로우를 위한 권장 사항
LLM 전처리 워크플로우에서는 다음과 같은 두 단계 접근 방식을 권장합니다:
- 처음에는
trafilatura사용: 초기 콘텐츠 추출을 위해 사용하세요. 이는 내비게이션, 광고, 불필요한 요소를 지능적으로 제거하면서도 주요 콘텐츠를 보존합니다. - 복잡한 문서의 경우
html-to-markdown사용: 테이블과 코드 블록이 포함된 기술 문서와 같은 정확한 구조 보존이 필요한 문서에 사용하세요.
이 조합은 실제 시나리오의 95%를 효과적으로 처리합니다.
다음 단계
Markdown, LaTeX, PDF 처리, 문서 인쇄 워크플로우에 대한 더 많은 가이드는 2026년 문서 도구: Markdown, LaTeX, PDF 및 인쇄 워크플로우를 참조하세요.
모든 도구(예외는 html2text)는 활발히 유지되고 있으며, 생산성에 적합합니다. 다음을 수행하는 것이 좋습니다:
- 사용 사례에 맞는 2~3개의 라이브러리를 설치하세요.
- 실제 HTML 샘플로 테스트하세요.
- 일반 문서 크기로 성능을 벤치마킹하세요.
- 출력 품질을 기준으로 선택하세요. 속도만으로는 선택하지 마세요.
HTML-to-Markdown 변환을 위한 Python 생태계는 매우 성숙해졌으며, 각 도구는 그 목적에 적합한 선택이 될 수 있습니다.
추가 자료
참고: 이 비교는 공식 문서, 커뮤니티 피드백 및 라이브러리 아키텍처 분석을 바탕으로 작성되었습니다. 성능 특성은 일반적인 사용 패턴을 대표합니다. 특정 사용 사례에 대해서는 실제 HTML 샘플로 자체 벤치마킹을 수행하세요.