0
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?

PythonでMarkdownソフトを作る

Last updated at Posted at 2025-02-18

🚀 Python + HTML で作る Markdown エディタ & サーバー(保存失敗のデバッグ対応)

このコードは Python + HTML を使って Markdown を編集・プレビューし、.md として保存できるエディタ を実装するものです。

保存ボタンを押したらファイル名を入力し、.md として保存
Markdown をリアルタイムでプレビュー表示
Python サーバー経由で .md ファイルの保存・管理が可能
保存失敗時のエラーを詳細表示


📂 プロジェクト構成

📁 プロジェクトフォルダ
 ├── markdown_server.py  # Python サーバー (Markdown ファイルの保存 & 読み込み)
 ├── markdown_editor.html  # HTML + JavaScript (Markdown エディタ & プレビュー)
 ├── saved_notes/  # `.md` ファイルの保存先
 └── saved_images/  # 画像ファイルの保存先

📝 markdown_server.py(Python サーバー)

import http.server
import socketserver
import json
import os

PORT = 8000
SAVE_DIR = "saved_notes"

# 保存フォルダを作成(なければ)
if not os.path.exists(SAVE_DIR):
    try:
        os.makedirs(SAVE_DIR)
        print(f"📁 フォルダ '{SAVE_DIR}' を作成しました。")
    except Exception as e:
        print(f"❌ フォルダ作成失敗: {e}")

class MarkdownServer(http.server.SimpleHTTPRequestHandler):
    def do_POST(self):
        if self.path == "/save":
            try:
                content_length = int(self.headers.get("Content-Length", 0))
                if content_length == 0:
                    raise ValueError("受信データが空です")

                post_data = self.rfile.read(content_length).decode("utf-8")
                print(f"📥 受信データの長さ: {content_length}")
                print(f"📥 受信データの中身: {post_data}")

                try:
                    data = json.loads(post_data)
                except json.JSONDecodeError as json_error:
                    print(f"❌ JSON パースエラー: {json_error}")
                    self.send_response(400)
                    self.end_headers()
                    self.wfile.write(f"❌ JSON パースエラー: {json_error}".encode("utf-8"))
                    return

                # ファイル名のバリデーション
                filename = data.get("filename", "").strip()
                content = data.get("content", "")

                if not filename:
                    raise ValueError("❌ ファイル名が空です")

                filename = os.path.basename(filename)  # ディレクトリ名を除外
                if not filename.endswith(".md"):
                    filename += ".md"

                filepath = os.path.join(SAVE_DIR, filename)
                print(f"📂 保存先: {filepath}")

                # 書き込み時のエラーハンドリング
                try:
                    with open(filepath, "w", encoding="utf-8") as f:
                        f.write(content)
                    self.send_response(200)
                    self.end_headers()
                    self.wfile.write(f"{filename} に保存しました!".encode("utf-8"))
                    print(f"{filename} に保存成功!")
                except OSError as write_error:
                    print(f"❌ 書き込みエラー: {write_error}")
                    self.send_response(500)
                    self.end_headers()
                    self.wfile.write(f"❌ 書き込みエラー: {write_error}".encode("utf-8"))

            except ValueError as value_error:
                print(f"❌ 値エラー: {value_error}")
                self.send_response(400)
                self.end_headers()
                self.wfile.write(f"❌ 値エラー: {value_error}".encode("utf-8"))
            except Exception as e:
                print(f"❌ その他のエラー: {e}")
                self.send_response(500)
                self.end_headers()
                self.wfile.write(f"❌ その他のエラー: {e}".encode("utf-8"))

# サーバー起動
try:
    with socketserver.TCPServer(("", PORT), MarkdownServer) as httpd:
        print(f"✅ サーバーが起動しました: http://localhost:{PORT}")
except Exception as e:
    print(f"❌ サーバー起動エラー: {e}")
    ---

## **📝 `markdown_editor.html`(Markdown エディタ)**
```html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Markdown Editor</title>
    <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
    <style>
        body { font-family: Arial, sans-serif; display: flex; height: 100vh; margin: 0; }
        #editor-container, #preview-container {
            width: 50%;
            padding: 10px;
            overflow: auto;
            box-sizing: border-box;
        }
        #editor-container {
            border-right: 1px solid #ccc;
        }
        #editor {
            width: 100%;
            height: 90%;
            font-size: 16px;
            padding: 10px;
            box-sizing: border-box;
            resize: none;
        }
    </style>
    <script>
        function updatePreview() {
            let mdText = document.getElementById("editor").value;
            document.getElementById("preview").innerHTML = marked.parse(mdText);
        }

        function saveMarkdown() {
            let mdText = document.getElementById("editor").value;
            let filename = prompt("保存するファイル名を入力(.mdを省略可)", "markdown_note");

            if (!filename) {
                alert("ファイル名が入力されていません。");
                return;
            }
            if (!filename.endsWith(".md")) {
                filename += ".md";
            }

            fetch("http://localhost:8000/save", {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({ filename: filename, content: mdText })
            })
            .then(response => response.text())
            .then((message) => {
                if (message.includes("")) {
                    alert("保存に失敗しました: " + message);
                } else {
                    alert(`"${filename}" に保存しました!`);
                }
            })
            .catch(error => alert("保存に失敗しました!\nエラー詳細: " + error));
        }
    </script>
</head>
<body>
    <div id="editor-container">
        <button onclick="saveMarkdown()">📝 保存</button>
        <textarea id="editor" oninput="updatePreview()"># Markdown Editor

## ✅ チェックボックス
- [ ] 未完了のタスク
- [x] 完了したタスク

## 🔹 引用
> これは引用のサンプルです

## 📌 コードブロック
\`\`\`python
print("Hello, Python!")
\`\`\`

        </textarea>
    </div>
    <div id="preview-container">
        <div id="preview"></div>
    </div>
</body>
</html>

📌 使い方

  1. Pythonサーバーを起動

    python markdown_server.py
    

    Serving at http://localhost:8000 と表示されたらOK!

  2. ブラウザで markdown_editor.html を開く

    • Markdown をエディタに入力
    • 「📝 保存」ボタンを押し、ファイル名を入力
    • saved_notes/.md が正しく保存されるか確認
    • エラーが出る場合はターミナルに詳細エラーが表示される

0
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
0
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?