Python: уроки, справочник и задачи

Библиотека markdown: из Markdown в HTML на Python

Раздел: Модули и библиотеки Python · Обновлено 31.10.2026

Python Markdown - это библиотека markdown, которая превращает текст в разметке Markdown в готовый HTML. Ее используют в генераторах документации, блогах на Flask и Django, при сборке отчетов. В статье показаны установка, базовая конвертация, подключение расширений для таблиц, кода и оглавления, работа с файлами и защита от опасного HTML в пользовательском тексте.

Python markdown
Фото: George E. Koronaios / CC BY-SA 4.0, Wikimedia Commons
Содержание статьи
  1. Установка и первая конвертация
  2. Какой синтаксис понимает библиотека
  3. Подключение расширений
    1. Таблицы и блоки кода
    2. Оглавление через toc
  4. Класс Markdown и работа с файлами
  5. Безопасность при выводе пользовательского текста
  6. Альтернативные библиотеки
  7. Частые вопросы
    1. Почему не работает таблица или блок кода в тройных кавычках?
    2. Почему вложенный список выводится одним уровнем?
    3. Как превратить HTML обратно в Markdown?
    4. Как получить чистый текст без разметки?

Установка и первая конвертация

Библиотека не входит в стандартную поставку Python, ее ставят через pip. Пакет называется Markdown, а импортируется как markdown.

pip install markdown

Основная функция markdown.markdown() принимает строку и возвращает строку с HTML. Обертку html и body она не добавляет, результат готов для вставки в шаблон страницы.

import markdown

text = "# Заголовок\n\nЭто *текст* в формате **Markdown**"
html = markdown.markdown(text)
print(html)
# <h1>Заголовок</h1>
# <p>Это <em>текст</em> в формате <strong>Markdown</strong></p>

Для быстрой проверки файла есть запуск из командной строки: python -m markdown notes.md > notes.html.

Какой синтаксис понимает библиотека

Без расширений Python-Markdown следует исходному описанию Markdown от Джона Грубера. В таблице показано, во что превращаются основные элементы.

MarkdownHTML
# Текст ... ###### Текстh1 ... h6
*курсив*, **жирный**em, strong
[текст](https://site.ru)a href
![подпись](img.png)img
- пункт или 1. пунктul / ol с li
> цитатаblockquote
`код`code
строка с отступом 4 пробелаpre с code
---hr

Есть отличия от GitHub-диалекта. Вложенные списки требуют отступа ровно в 4 пробела, двух пробелов недостаточно. Перенос строки внутри абзаца не создает тег br, для этого нужно расширение nl2br. Таблицы и блоки кода в тройных обратных кавычках тоже работают только с расширениями.

Подключение расширений

Расширения передаются списком в параметре extensions. Встроенные расширения указывают коротким именем, сторонние ставят отдельно через pip.

РасширениеЧто добавляет
tablesтаблицы с разделителем |
fenced_codeблоки кода в тройных обратных кавычках
codehiliteподсветку кода через Pygments
tocid у заголовков и оглавление
footnotesсноски
nl2brbr на месте одиночного переноса
sane_listsболее предсказуемое поведение списков
extraнабор: tables, fenced_code, footnotes, abbr, attr_list, def_list, md_in_html

Таблицы и блоки кода

Расширение extra сразу включает самые востребованные возможности, поэтому его часто подключают по умолчанию.

import markdown

text = """
| Метод | Описание |
|-------|----------|
| get   | чтение   |

```python
print("hi")
```
"""
html = markdown.markdown(text, extensions=["extra"])
print(html)

Для цветной подсветки добавьте codehilite и установите пакет Pygments. Библиотека разметит код классами, а цвета подключаются отдельным CSS-файлом, который генерирует сам Pygments.

Оглавление через toc

Расширение toc добавляет заголовкам атрибуты id и собирает оглавление. Его можно вставить в текст маркером [TOC] или взять из атрибута объекта после конвертации. Для кириллицы удобно задать функцию slugify с поддержкой Unicode.

import markdown
from markdown.extensions.toc import slugify_unicode

md = markdown.Markdown(extensions=["toc"],
                       extension_configs={"toc": {"slugify": slugify_unicode}})
html = md.convert("## Установка\n\n## Настройка")
print(html)    # <h2 id="установка">Установка</h2> ...
print(md.toc)  # <div class="toc"><ul>...</ul></div>

Класс Markdown и работа с файлами

Функция markdown.markdown() при каждом вызове заново создает парсер. Если нужно обработать много документов, выгоднее один раз создать объект markdown.Markdown и вызывать convert(). Между документами вызывайте reset(), чтобы сбросить состояние расширений, например сноски и оглавление предыдущего текста.

from pathlib import Path
import markdown

md = markdown.Markdown(extensions=["extra", "toc"])
for src in Path("docs").glob("*.md"):
    body = md.convert(src.read_text(encoding="utf-8"))
    src.with_suffix(".html").write_text(body, encoding="utf-8")
    md.reset()

Указывайте кодировку явно: в Windows без encoding="utf-8" русский текст прочитается неправильно. Подробнее о режимах открытия и кодировках рассказано в статье работа с текстовым файлом. Для одиночных файлов есть функция markdown.markdownFromFile(input=..., output=...).

Безопасность при выводе пользовательского текста

Python-Markdown пропускает встроенный HTML без изменений. Если пользователь напишет в комментарии тег script, он попадет на страницу как есть. Библиотека не занимается очисткой, поэтому для текста из форм результат нужно пропускать через санитайзер с белым списком тегов, например пакет nh3 или bleach.

import markdown
import nh3

user_text = "**Привет** <script>alert(1)</script>"
safe_html = nh3.clean(markdown.markdown(user_text))
print(safe_html)  # <p><strong>Привет</strong> </p>

Во Flask готовый HTML передают в шаблон через фильтр |safe или обертку Markup, иначе Jinja экранирует теги и пользователь увидит их текстом. Делать это можно только с уже очищенной строкой. Как устроены маршруты и шаблоны, описано в статье основы Flask.

Альтернативные библиотеки

Кроме Python-Markdown, для конвертации используют еще два популярных пакета. Выбор зависит от того, какой диалект Markdown нужен и важна ли скорость.

Описание всех параметров и встроенных расширений есть в документации Python-Markdown.

Частые вопросы

Ответы на вопросы, которые возникают при первом использовании библиотеки.

Почему не работает таблица или блок кода в тройных кавычках?

Эти элементы не входят в базовый синтаксис. Подключите расширения tables и fenced_code или сразу extra.

Почему вложенный список выводится одним уровнем?

Python-Markdown требует отступ в 4 пробела для вложенного пункта. С отступом в 2 пробела элементы окажутся в одном списке.

Как превратить HTML обратно в Markdown?

Библиотека работает только в одну сторону. Для обратного преобразования используют отдельные пакеты, например markdownify или html2text.

Как получить чистый текст без разметки?

Сконвертируйте Markdown в HTML, а затем извлеките текст парсером, например через BeautifulSoup(html, "html.parser").get_text().