MarkdownをPythonライブラリとして使用する
初回公開:2018/01/01
最終更新:2018/01/13
「Library Reference — Python Markdown」をつたない翻訳,勝手な解釈。
【 目次 】
まず第一にPython-Markdownは、Markdown構文をHTMLに変換するためにさまざまなプロジェクトで使用されるPythonライブラリモジュールとなる事を目指しています。
基本
markdownをモジュールとして使用するには:
import markdown html = markdown.markdown(your_text_string)
詳細
Python-Markdownには、パブリッククラスmarkdown.Markdown
をラップする2つのパブリック関数(markdown.markdown
およびmarkdown.markdownFromFile
)が用意されています。
一度に1つのドキュメントを処理している場合、これらの関数が必要に応じて機能します。
ただし、複数のドキュメントを処理する必要がある場合は、markdown.Markdownクラスの1つのインスタンスを作成し、複数のドキュメントを渡すと便利です。
1つのインスタンスを使用する場合は、resetメソッドを適切に呼び出すようにしてください(下記を参照)。
markdown.markdown (text [, **kwargs])
markdown.markdown
関数では、次のオプション(引数)を使用できます。
-
text
(必須):ソースのUnicode文字列。重要
Python-Markdownは、入力としてUnicodeを想定しています(いくらかのシンプルなASCII文字列でも動作するかもしれません)、
そしてUnicodeとして出力を返します。
エンコードされた文字列を渡さないでください!
あなたの入力が(UTF-8などのように)エンコードされている場合、それをデコードするのはあなたの責任です。
例えば:input_file = codecs.open("some_file.txt", mode="r", encoding="utf-8") text = input_file.read() html = markdown.markdown(text)
出力をディスクに書き込む場合は、自分でエンコードする必要があります。
output_file = codecs.open("some_file.html", "w", encoding="utf-8", errors="xmlcharrefreplace" ) output_file.write(html)
-
extensions
: extensionsのリスト。Python-Markdownは、第三者が独自の追加や変更を構文に追加してパーサーに拡張機能extensionsを記述するためのAPIを提供します。
一般的に使用されるいくつかのextensionsが、markdownライブラリに付属しています。
使用可能なextensionsのリストについては、extensionのドキュメントを参照してください。extensionsのリストは、extensionsのインスタンスおよび/またはextensionの名前を示す文字列を含むことができます。
extensions=[MyExtension(), 'path.to.my.ext']
注意
好ましい方法は、extensionのインスタンスを渡すことです。
文字列は、Extensionクラスを直接(コマンドラインまたはテンプレートから)インポートすることが不可能な場合にのみ使用してください。extensionのインスタンスを渡すときは、おのおののクラスのインスタンスは
markdown.extensions.Extension
のサブクラスでなければならず、クラスインスタンスを開始するときはextension_configsキーワードを使用するのではなく、いくつかの設定オプション(configuration options)を定義すべきです。
例えば:from markdown.extensions import Extension class MyExtension(Extension): # define your extension here... markdown.markdown(text, extensions=[MyExtension(option='value')])
extension名が文字列として提供されている場合、そのextensionはPYTHONPATH上のPythonモジュールとしてインポート可能でなければなりません。
Pythonのドット表記法がサポートされています。
したがって、'extra' extensionをインポートするには、 extensions=['markdown.extensions.extra']とすることができます。さらに、名前にクラスを指定することもできます。 クラスは名前の末尾にあり、モジュールのコロンで区切られていなければなりません。
したがって、このようなクラスをインポートする場合は、次のようにします。:
from path.to.module import SomeExtensionClass
名前付きextensionは次の文字列で構成されます。:
"path.to.module:SomeExtensionClass"
注意
同じモジュール内で複数のextensionが定義されている場合は、クラス名を指定するだけで済みます。
Python-Markdownに付属するextensionsには、クラス名を指定する必要はありません。
そうすることで、パーサの動作には影響しません。extensionを名前(文字列)で読み込むときは、
extension_configs
キーワードを使用してextensionにコンフィギュレーションの設定を渡すことができます 。もまた参照
extensionsを作成するための助けとして、Extension APIのドキュメントを参照してください。
-
extension_configs
: extensionsのコンフィグ設定の辞書。すべてのコンフィギュレーション設定は、(文字列として)名前でロードされたextensionsにのみ渡されます。
クラスのインスタンスとしてextensionsをローディングする時には、コンフィギュレーション設定は初期化時にクラスに直接渡される。注意
好ましい方法は、extensionのインスタンスを渡すことです。
extension_configs
キーワードをまったく使用する必要はありません。
詳細については、extensionsキーワードを参照してください。コンフィギュレーション設定の辞書は、次の形式である必要があります。
extension_configs = { 'extension_name_1': { 'option_1': 'value_1', 'option_2': 'value_2' }, 'extension_name_2': { 'option_1': 'value_1' } }
ヘルプに対して使われているextensionのドキュメントを参照してください。
そのextensionのコンフィギュレーション設定を指定します。 -
output_format
: 出力フォーマット。サポートされているフォーマットは:
"xhtml1"
: XHTML 1.x を出力 デフォルト。"xhtml5"
: HTML5のXHTMLスタイルタグを出力。"xhtml"
: サポートされている最新バージョンのXHTML(現在のXHTML 1.1)を出力。"html4"
: HTML4を出力。"html5"
: HTML5のHTMLスタイルタグを出力。"html"
: サポートされているHTMLの最新バージョン(現在HTML 4)を出力。
値は、小文字でも大文字でもかまいません。
警告
より一般的なフォーマット("xhtml" or "html")として、その時点で意味がある場合、将来変化する可能性がある,より具体的なフォーマット("xhtml1", "html5", & "html4")を使う事が提案されます。
-
safe_mode
: 生のHTMLを許可しません。警告
"
safe_mode`"は推奨されておらず、使われるべきではありません。
(BLEACHのような)HTMLサニタイザは、信頼できないユーザーによって提出されたmarkdownテキストに対応するためのより良い解決方法を与えます。
import markdown import bleach html = bleach.clean(markdown.markdown(untrusted_text))
詳細は、リリースノートを参照してください。
受け入れられる値は次のとおりです。
-
False
(デフォルト):生のHTMLは変更されずに渡されます。 -
replace
:すべてのHTMLブロックをhtml_replacement_textに割り当てられたテキストに置き換えます。
下位互換性を維持のため、safe_mode = Trueを設定すると、safe_mode = 'replace'と同じ効果が得られます。
safe_mode = True
はsafe_mode = 'replace'
と同じ効果を持ちます。生のHTMLをデフォルト以外のものに置き換えるには、次のようにします。
md = markdown.Markdown(safe_mode = 'replace'、 html_replacement_text = ' - RAW HTML NOT ALLOWED--')
-
remove
:すべての生のHTMLは完全にテキストから取り除かれます。
著者には警告はありません。 -
`escape':生のHTMLはすべてエスケープされ、文書に含まれます。
たとえば、次のソースがあります。
Foo <b>bar</b>.
次のHTMLになります:
<p>Foo <b>bar</b>.</p>
注意
"safe_mode"は
enable_attributes
optionのデフォルト値も変更します。 -
-
html_replacement_text
: テキストはsafe_modeがreplace
に設定された時に使われます。
デフォルトは[HTML_REMOVED]
です。Warning
"
html_replacement_text
"は推奨されておらず、使われるべきではありません。
詳細は、リリースノートを参照してください。 -
tab_length
: ソースのタブの長さ。デフォルト:4 -
enable_attributes
: 属性の変換を有効にします。
デフォルトはTrue
,もしsafe_mode
が有効でないならその場合はFalse
です。注意
safe_mode
はデフォルトを上書きするだけです。
もしenable_attributes
が明示的に設定されているなら、明示的な値はsafe_mode
に関係なく使用されます。
けれども、これはあなたのドキュメントに信頼されないユーザのJavaScriptの注入を潜在的に許す事になります。 -
smart_emphasis
:_connected_words_
を知的に扱う。 -
lazy_ol
: 順序付きリストの最初の項目の数値を無視します。
デフォルト: True以下のリストが与えられます:
4. Apples 5. Oranges 6. Pears
デフォルトではmarkdownは最初の行が4から始まっている事実を無視して、HTMLリスト項目を1から始めます。
もし、lazy_ol
がFalse
に設定されているなら、markdownのHTML出力は次のようになるでしょう:<ol start="4"> <li>Apples</li> <li>Oranges</li> <li>Pears</li> </ol>
訳者による蛇足
markdown.markdownFromFile (**kwargs)
いくつかの例外を除いて、 markdown.markdownFromFile
はmarkdown.markdown
と同じオプションを受け付ける。
text
引数(またはUnicodeの)文字列は受け入れませんが、かわりに次の必須のオプションを受け付ける。
代わりに、次の必須オプションを受け入れます。
-
input
(必須): ソーステキストファイル。input
は3つのオプションのうちの1つを設定します:- ファイルシステム上の読み取り可能なファイルへのパスを含む文字列,
- 読み取り可能なfile-like object,
- もしくは
None
(デフォルト) これはstdin
から読み込みます。
-
output
: 出力が書き込まれるターゲット。output
は3つのオプションのうちの1つが設定できます:- ファイルシステム上の書き込み可能ファイルへのパスを含む文字列,
- 書き込み可能なfile-like object,
- もしくは
None
(デフォルト)stdout
へ書き込みます。
-
encoding
: ソーステキストファイルのエンコーディング。 デフォルトは"utf-8"
。inputとoutput に対して常に同じエンコーディングが使われます。xmlcharrefreplace
エラーハンドラは、出力をエンコードする際に使用されます。注意
これは、Python-MarkdownにおいてUnicodeのデコードとエンコードを指定する唯一の場所です。
このやや素朴な解決策(naive solution)が あなたの具体的な必要としている用途に沿わないなら、エンコード/デコードの用途に沿う処理をする独自のコードを書くことをお勧めします
訳者による蛇足
- naive solution
- file-like objectというのは
markdown.Markdown ([**kwargs])
クラスが初期化時にソーステキスト文字列を受け取らない事を除いて、markdown.Markdown
クラスを初期化するときにもmarkdown.markdown
関数と同じオプションが利用できます。
むしろ、ソーステキスト文字列を2つのインスタンスメソッドのいずれかに渡す必要があります。
-
Markdown.convert(source)
source
テキストはmarkdown.markdown
関数のtext
引数と同じ要件を満たさなければなりません。複数のテキストを、おのおののテキストに対して新しいインスタンスを作成する事なしに処理したいなら、このメソッドを使うべきです。
md = markdown.Markdown() html1 = md.convert(text1) html2 = md.convert(text2)
どのオプションおよび/またはextensionsが使用されているかに応じて、パーサは、
convert
関数への各呼び出しの間に状態をリセットする必要があります。
さもないと、パフォーマンスが大幅におちる可能性があります。html1 = md.convert(text1) md.reset() html2 = md.convert(text2)
より簡潔に記述するために、
reset
をメソッドチェインして使う事もまたできる:html3 = md.reset().convert(text3)
-
Markdown.convertFile(**kwargs)
このメソッドの引数は
markdown.markdownFromFile
関数の同名の引数(input
,output
,encoding
)と同じです。
convert
と同様に、おのおののドキュメントのためにクラスの新しいインスタンスを作成する事なしに、複数のファイルを処理するためにこのメソッドが使われるべきです。
convert
の場合のように、状態はおのおののconvertFile
の呼び出しの間にreset
される必要があります。
訳者による蛇足
safe_mode
とenable_attributes
safe_mode
とenable_attributes
の意味がよくわからなかったので、ググってみると
- appsec - How do I use Markdown securely? - Information Security Stack Exchange
- #17837 (Markdown filter "safe" mode is vulnerable to e.g. 'onclick' attributes) – Django
どうやらXSSの脆弱性対策のためのオプションらしい。
XSS(クロスサイトスクリプティング)
XSSによる脆弱性とは
静的ページでのmarkdownをhtmlに変換して表示するのは問題ないが、ユーザから入力されたmarkdownテキストを自動的にHTMLに変換して表示させるWebサイトを構築したとすると、markdownテキストにJavaScriptのコードが埋め込まれた(JavaScriptインジェクション)入力を受け取る可能性がある。
これmarkdownテキストをそのままhtmlに変換して表示してしまうと不正なJavaScriptのコードを実行させられてしまう。
これを防ぐためにはsafe_modeというオプションがあってサニタイジング等の処理をおこなってくれるらしい。
HTMLサニタイズ
- サニタイジング(エスケープ)とは?HTML特殊文字を無害化しない事による脅威と対策のまとめ
- XSSを防ぐために不可欠なサニタイジング(無害化):クロスサイトスクリプティング対策の基本(後編) - @IT
しかし、safe_modeは非推奨であって、別途、BLEACHなどのHTMLサニタイズするライブラリを使って自前でHTMLサニタイズを行ったほうがいいらしい。
enable_attributes
はsafe_mode
と関係あるらしいのだがようわからん。
BLEACH
BLEACHというのは
- Bleach — Bleach 2.1.2 20171207 documentation
- GitHub - mozilla/bleach: Bleach is an allowed-list-based HTML sanitizing library that escapes or strips markup and attributes
- HTMLサニタイズするライブラリbleachを試してみた - Ian Lewis
HTMLパーサー
余談ではあるがHTMLパーサーというのがあって
BeautifulSoup
pythonではBeautifulSoupというHTMLパーサーが有名らしい。
smart_emphasis
smart_emphasisというのは、_
によるemタグへの変換を単語の区切りかどうかを自動的に判断してより賢くおこなってくれるという事らしい。
smart_emphasisがFalse
になっていると、単純に単語の区切りは無視して_
が現れてから次の_
までをemphasis(emタグに変換)するようだ。
import markdown markdon_text='it is _connected_words_ or _connected_words_long_time_ for me' print markdown.markdown(markdon_text) print markdown.markdown(markdon_text,smart_emphasis=False);
実行結果
<p>it is <em>connected_words</em> or <em>connected_words_long_time</em> for me</p> <p>it is <em>connected</em>words<em> or </em>connected<em>words</em>long<em>time</em> for me</p>
naive solution
naive solutionという文言をどう訳せばよいか迷ってしまったので