1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Jupyter Notebook → PDF 変換方法の比較表 + Playwright 経由変換例

Last updated at Posted at 2025-09-17

Jupyter Notebook → PDF 変換方法の比較表をまとめました (以下)。誤りがありましたらご指摘いただけますと幸いです。

image.png

【補足】HTML オブジェクト出力について

例えば Pandas Styler でデータフレーム内の負の数を赤くしたり、最大値を強調したりすることがあるかもしれませんが、これは TeX 経由では PDF 変換できません。

下図の左側は後述のスクリプトで HTML 経由で PDF 化したノートブック、右側は jupyter nbconvert --to pdf Untitled.ipynb コマンドで (TeX 経由で) PDF 化したノートブックです。左側ではデータフレームが表示できていますが、右側は表示できていません。

image.png

つまり、TeX 経由の PDF 変換では display(HTML(...)) などといった HTML としてレンダリングされる要素の変換には対応しておらず、表示できません (なお、 df.styledisplay(HTML(...)) としなくてもセル末尾でこれを返せばノートブック上にレンダリングされますが、結局 HTML としてレンダリングされるのでどのみち表示できません)。

【おまけ】Playwright 経由変換スクリプト

上図の左側の、HTML 経由 PDF を生成したときに使用したスクリプトは以下です。コード内かどうかの判定は適当にやっています (Beautiful Soup をつかった方がメンテ性のよいスクリプトになるとは思います)。

  • Playwright の pdf メソッドのドキュメントは以下です。余白 margin はデフォルトでゼロになっていて以下では変更していませんが好きに変更することもできます (はず)。
    Page | Playwright Python
script.py
from playwright.sync_api import sync_playwright
import subprocess
import re

def repl(match):
    spaces = len(match.group(1))
    return '\u2423' * spaces  # 行頭の空白と同じ個数の空白記号を返す

# ---------- (1) HTML 変換 ----------
subprocess.run(
    ['jupyter', 'nbconvert', '--to', 'html', 'Untitled.ipynb'],
    check=True
)

# ---------- (2) HTML 読み込み兼書き換え ----------
code_flag = False
html = ''
with open('Untitled.html', encoding='utf8') as ifile:
    for line in ifile:
        # コード内かどうかの判定
        if '<div class="highlight hl-ipython3"><pre>' in line:
            code_flag = True
        if code_flag and '</pre></div>' in line:
            code_flag = False

        # head が終わる直前に独自スタイルを挿入
        if '</head>' in line:
            line += (
                '<style type="text/css">\n'
                'div.jp-MarkdownOutput {\n'
                '  font-family: "Rounded Mplus 1c";\n'
                '  line-height: 1.2;\n'
                '}\n'
                'body {\n'
                '  margin: 0 !important;\n'
                '  padding: 0 !important;\n'
                '}\n'
                '</style>\n'
            )

        # コード内なら行頭の空白を空白記号に置換
        if code_flag:
            line = re.sub(r'^( +)', repl, line)
        html += line

# デバッグ用
# with open('out.html', mode='w', encoding='utf8') as ofile:
#     ofile.write(html)


# ---------- (3) 読み込んだ HTML を PDF として保存 ----------
with sync_playwright() as p:
    browser = p.chromium.launch()
    page = browser.new_page()
    page.set_content(html)
    page.pdf(
        path='Untitled.pdf',
        format='A4',
        print_background=True,
        scale=0.9,
    )
    browser.close()
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?