Python入門トップページ


目次

  1. 仮想環境を構築し,watchdog をインストールする
  2. Watchdog でフォルダを監視する
  3. 新しいファイルを検知する
  4. 検知した新しいファイルを待ち行列フォルダに移動する
  5. 文字起こし処理用のワーカープログラムのひな形を作成する
  6. ワーカープログラムを常駐化する
  7. フォルダ監視とワーカープログラムでパイプライン処理する
  8. 処理用フォルダを設置してそこで処理を行う
  9. ファイルサイズの変化を監視する
  10. サイズの大きなファイルのコピーに対応する
  11. タイムスタンプを表示する
  12. Subprocess で外部コマンドを起動する
  13. WhisperX の設定を行う
  14. ワーカープログラムで音声データからの文字起こしを実行する
  15. 文字起こし結果を完了用フォルダに移動する
  16. ログを保存し例外を処理する
  17. サブフォルダに結果を格納する
  18. Ollama をインストールする
  19. Python から Ollama にプロンプトを送る
  20. Ollama 処理を関数化する
  21. 文字起こしデータから議事録を作成する
  22. サイズの大きなテキストファイルにも対応する
  23. ワーカープログラムで文字起こし結果から議事録を生成する
  24. 議事録をマークダウンファイルに出力する
  25. 文字コードを強制的に指定する

フォルダ監視により,音声ファイルから文字起こしと議事録生成を自動化しよう

議事録をマークダウンファイルに出力する

前のページでは画面に出力されていた議事録をマークダウン形式のファイルに保存するように修正します.具体的には,次のとおり出力先のファイルパスを指定し,printではなくファイルに書き出すだけです.

worker.py
from pathlib import Path
import shutil
import time
import datetime
import subprocess

BASE_DIR = Path(__file__).parent
QUEUE_DIR = BASE_DIR / "queue"
WORKING_DIR = BASE_DIR / "working"
DONE_DIR = BASE_DIR / "done"
ERROR_DIR = BASE_DIR / "error"

# ディレクトリを作っておく
QUEUE_DIR.mkdir(parents=True, exist_ok=True)
WORKING_DIR.mkdir(parents=True, exist_ok=True)
DONE_DIR.mkdir(parents=True, exist_ok=True)
ERROR_DIR.mkdir(parents=True, exist_ok=True)

def ask_ollama(prompt):

    result = subprocess.run(
        ["ollama", "run", "qwen3:8b"],
        input=prompt,
        capture_output=True,
        text=True,
        encoding="utf-8"
    )

    return result.stdout

try:
    while True:
        for src in QUEUE_DIR.glob("*.m*"): # 監視するファイルの拡張子
            print(f"[{datetime.datetime.now().strftime('%H:%M:%S.%f')}] ----------------")
            print(f"[{datetime.datetime.now().strftime('%H:%M:%S.%f')}] 処理開始: {src.name}")
            working_file = WORKING_DIR / src.name
            transcription_dir = WORKING_DIR / src.stem
            transcription_dir.mkdir(parents=True, exist_ok=True) # ディレクトリを作っておく
            log_file = transcription_dir / "whisperx.log"
            shutil.move(src, working_file)
            # 文字起こし -----------------------------------
            print(f"[{datetime.datetime.now().strftime('%H:%M:%S.%f')}] 作業開始: {working_file}")
            print(f"[{datetime.datetime.now().strftime('%H:%M:%S.%f')}] 出力先 : {transcription_dir}")
            print(f"[{datetime.datetime.now().strftime('%H:%M:%S.%f')}] 文字起こし処理中...")
            try:
                with open(log_file, "w", encoding="utf-8") as f:
                    subprocess.run([
                        "whisperx",
                        "--model", "turbo", # tubo / large ...
                        "--language", "ja",
                        # "--device", "cuda",  # NVIDIA GPU を利用できる場合
                        "-o", str(transcription_dir),
                        "--diarize",  # 話者分離
                        str(working_file)
                    ],
                    stdout=f,
                    stderr=subprocess.STDOUT,
                    check=True)
            except subprocess.CalledProcessError:
                print(f"[{datetime.datetime.now().strftime('%H:%M:%S.%f')}] WhisperXの処理に失敗しました")
                dt = datetime.datetime.now()
                err_dir_name = f"{dt.strftime('%Y%m%d-%H%M%S')}_{src.stem}"
                err_dst = ERROR_DIR / err_dir_name / src.name
                err_transcription_dir = ERROR_DIR / err_dir_name / src.stem
                err_transcription_dir.mkdir(parents=True, exist_ok=True) # ディレクトリを作っておく
                shutil.move(working_file, err_dst)
                shutil.move(transcription_dir, err_transcription_dir)
                print(f"[{datetime.datetime.now().strftime('%H:%M:%S.%f')}] 失敗: {err_dst}")
                continue
            time.sleep(3)
            # 議事録生成 -----------------------------------
            transcription_file_name = src.stem + ".txt"
            transcription_file_path = transcription_dir / transcription_file_name
            minutes_file_name = src.stem + ".md" # 議事録ファイル名
            minutes_file = transcription_dir / minutes_file_name
            print(f"[{datetime.datetime.now().strftime('%H:%M:%S.%f')}] 議事録生成中...")
            time.sleep(3)

            with open(transcription_file_path, encoding="utf-8") as f:
                transcript = f.read()

            prompt = f"""
            次の文字起こし結果から議事録を作成してください。

            {transcript}
            """

            minutes = ask_ollama(prompt)

            with open(minutes_file, "w", encoding="utf-8") as f:
                f.write(minutes)
            # print(minutes)
            # print("-----------------")
            print(f"[{datetime.datetime.now().strftime('%H:%M:%S.%f')}] 議事録生成完了")

            # 作業完了 → ファイルの移動 -----------------------------------
            dt = datetime.datetime.now()
            done_dir_name = f"{dt.strftime('%Y%m%d-%H%M%S')}_{src.stem}"
            done_file = DONE_DIR / done_dir_name / src.name
            done_transcription_dir = DONE_DIR / done_dir_name
            done_transcription_dir.mkdir(parents=True, exist_ok=True) # ディレクトリを作っておく
            shutil.move(working_file, done_file)
            shutil.move(transcription_dir, done_transcription_dir)
            print(f"[{datetime.datetime.now().strftime('%H:%M:%S.%f')}] 完了: {done_file}")
        time.sleep(1)

except KeyboardInterrupt:
    print(f"[{datetime.datetime.now().strftime('%H:%M:%S.%f')}] 停止します")

ターミナルを2個起動し,それぞれで watch.py と worker.py を実行します.

(py313watchdog) PS C:\Users\rinsaka\Documents\python\watchdog> python watch.py ⏎
(py313watchdog) PS C:\Users\rinsaka\Documents\python\watchdog> python worker.py ⏎

2つの音声ファイルを監視フォルダに格納することで「文字起こし」→「議事録作成」の処理が自動的に進みます.

(py313watchdog) PS C:\Users\rinsaka\Documents\python\watchdog> python watch.py
[18:28:26.637080] 新しいファイルを検出: C:\Users\rinsaka\Documents\python\watchdog\watch\voice-sample02.m4a
[18:28:26.637295] 新しいファイルの名前: voice-sample02.m4a
[18:28:36.638058] ファイルの受取りが完了しました
[18:28:36.638223] ファイルの移動開始: C:\Users\rinsaka\Documents\python\watchdog\queue\voice-sample02.m4a
[18:28:36.639905] ファイルの移動完了: C:\Users\rinsaka\Documents\python\watchdog\queue\voice-sample02.m4a
[18:28:36.640185] 新しいファイルを検出: C:\Users\rinsaka\Documents\python\watchdog\watch\voice-sample01.m4a
[18:28:36.640469] 新しいファイルの名前: voice-sample01.m4a
[18:28:46.641540] ファイルの受取りが完了しました
[18:28:46.641703] ファイルの移動開始: C:\Users\rinsaka\Documents\python\watchdog\queue\voice-sample01.m4a
[18:28:46.642439] ファイルの移動完了: C:\Users\rinsaka\Documents\python\watchdog\queue\voice-sample01.m4a
Ctrl + C
[18:30:23.425664] 停止します
(py313watchdog) PS C:\Users\rinsaka\Documents\python\watchdog>

ワーカープログラムの出力がかなりスッキリしました.もう少し出力を減らしても良いかもしれません.

(py313watchdog) PS C:\Users\rinsaka\Documents\python\watchdog> python worker.py
[18:28:37.423811] ----------------
[18:28:37.423911] 処理開始: voice-sample02.m4a
[18:28:37.439474] 作業開始: C:\Users\rinsaka\Documents\python\watchdog\working\voice-sample02.m4a
[18:28:37.439633] 出力先 : C:\Users\rinsaka\Documents\python\watchdog\working\voice-sample02
[18:28:37.439657] 文字起こし処理中...
[18:28:58.497520] 議事録生成中...
[18:29:24.910144] 議事録生成完了
[18:29:24.911474] 完了: C:\Users\rinsaka\Documents\python\watchdog\done\20261102-182924_voice-sample02\voice-sample02.m4a
[18:29:25.912150] ----------------
[18:29:25.912347] 処理開始: voice-sample01.m4a
[18:29:25.913838] 作業開始: C:\Users\rinsaka\Documents\python\watchdog\working\voice-sample01.m4a
[18:29:25.913935] 出力先 : C:\Users\rinsaka\Documents\python\watchdog\working\voice-sample01
[18:29:25.914049] 文字起こし処理中...
[18:29:54.316321] 議事録生成中...
[18:30:17.742677] 議事録生成完了
[18:30:17.743896] 完了: C:\Users\rinsaka\Documents\python\watchdog\done\20261102-183017_voice-sample01\voice-sample01.m4a
Ctrl + C
[18:30:24.377592] 停止します
(py313watchdog) PS C:\Users\rinsaka\Documents\python\watchdog>

全ての処理を終えたら完了用 done フォルダを再帰的に確認します.文字起こし結果のテキストファイル (*.txt) と議事録のマークダウンファイル (*.md) が出力されていることが分かりました.

(py313watchdog) PS C:\Users\rinsaka\Documents\python\watchdog> gci done -Recurse ⏎

    ディレクトリ:C:\Users\rinsaka\Documents\python\watchdog\done

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d----          2026/11/02    18:29                20261102-182924_voice-sample02
d----          2026/11/02    18:30                20261102-183017_voice-sample01

    ディレクトリ:C:\Users\rinsaka\Documents\python\watchdog\done\20261102-182924_voice-sample02

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d----          2026/11/02    18:29                voice-sample02
-a---          2026/10/27    12:39         554089 voice-sample02.m4a

    ディレクトリ:C:\Users\rinsaka\Documents\python\watchdog\done\20261102-182924_voice-sample02\voice-sample02

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a---          2026/11/02    18:28          58602 voice-sample02.json
-a---          2026/11/02    18:29           4261 voice-sample02.md
-a---          2026/11/02    18:28           1113 voice-sample02.srt
-a---          2026/11/02    18:28           1014 voice-sample02.tsv
-a---          2026/11/02    18:28           1005 voice-sample02.txt
-a---          2026/11/02    18:28           1096 voice-sample02.vtt
-a---          2026/11/02    18:28           3355 whisperx.log

    ディレクトリ:C:\Users\rinsaka\Documents\python\watchdog\done\20261102-183017_voice-sample01

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d----          2026/11/02    18:30                voice-sample01
-a---          2026/10/27    12:36         329637 voice-sample01.m4a

    ディレクトリ:C:\Users\rinsaka\Documents\python\watchdog\done\20261102-183017_voice-sample01\voice-sample01

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a---          2026/11/02    18:29          28431 voice-sample01.json
-a---          2026/11/02    18:30           3671 voice-sample01.md
-a---          2026/11/02    18:29            566 voice-sample01.srt
-a---          2026/11/02    18:29            505 voice-sample01.tsv
-a---          2026/11/02    18:29            494 voice-sample01.txt
-a---          2026/11/02    18:29            558 voice-sample01.vtt
-a---          2026/11/02    18:29           2994 whisperx.log

(py313watchdog) PS C:\Users\rinsaka\Documents\python\watchdog>

次のとおり,Get-Contentコマンドレットで文字起こしの結果を確認できます.

(py313watchdog) PS C:\Users\rinsaka\Documents\python\watchdog> Get-Content done\20261102-183017_voice-sample01\voice-sample01\voice-sample01.txt ⏎
[SPEAKER_00]: 日銀の上田総裁はきょう都内で講演し、中東情勢が不透明な状況が続いたとしても、利上げを行う可能性があるとの考えを示しました。日銀は今月15日から2日間、金融政策決定会合を開きます。会合を前に都内で講演した日銀の上田総裁は、
[SPEAKER_00]: 仮に中東情勢が不透明な状況が続くとしても、利上げに踏み切る可能性があるとの考えを示しました。
(py313watchdog) PS C:\Users\rinsaka\Documents\python\watchdog>

Get-Contentコマンドレットのエイリアス gc でも同様に生成された議事録も確認します.

(py313watchdog) PS C:\Users\rinsaka\Documents\python\watchdog> gc done\20261102-183017_voice-sample01\voice-sample01\voice-sample01.md ⏎
Thinking...
Okay, I need to create a meeting minutes based on the provided text. Let me start by understanding the content. The text mentions that the Bank of Japan's Governor Ueda gave a speech in Tokyo today, discussing the possibility of raising interest rates even if the Middle East situation remains uncertain. The BOJ is holding a two-day monetary policy decision meeting starting on the 15th. Ueda mentioned that even if the Middle East situation is unclear, there's a possibility of a rate hike.

First, I should structure the minutes with standard sections: date, time, location, attendees, agenda items, discussions, decisions, and next steps. However, the original text doesn't mention specific attendees or a formal meeting, just a speech before a policy meeting. So maybe the minutes should reflect the speech as part of the preparation for the meeting.

I need to note the key points: Ueda's speech, the uncertainty in the Middle East, the possibility of rate hike, the upcoming meeting dates. Also, the speaker mentions the speech was in Tokyo, so the location is Tokyo. The date is today, but the actual date isn't specified, so I'll use "today" as in the original. The meeting is scheduled for the 15th, but the exact time isn't mentioned.

I should make sure to capture the main message that despite the Middle East uncertainty, the BOJ might proceed with rate hikes. Also, the context of the policy meeting coming up. The minutes should be formal, concise, and include all the key information from the text without adding extra details. Let me check if there are any other details I might have missed. The original text has two speaker entries, but both are about the same speech, so I can combine them into one section. Alright, I'll structure the minutes accordingly.
...done thinking.

**議事録**
**日時**:令和X年X月X日(金曜日)
**場所**:東京都内(具体地未明示)
**出席者**:日銀総裁上田 昭一氏(主催者)

---

### **1. 講演の概要**
- **上田総裁の講演内容**
  - 中東情勢の不透明な状況が続く中でも、利上げの検討が進んでいることを示唆。
  - 今後、インフレ率や雇用市場の動向を注視しつつ、金融政策の方向性を調整する必要性を強調。
  - 今月15日に開催される金融政策決定会合を前に、市場の動向や国際情勢への対応を含む議論が求められると述べた。

---

### **2. 今後の予定**
- **金融政策決定会合**
  - **日時**:令和X年X月15日(木曜日)~16日(金曜日)
  - **場所**:日銀本店(東京都千代田区)
  - **議題**:利上げの検討、物価上昇の持続性、金融緩和の効果の評価、国際情勢への影響等

---

### **3. 主なコメント**
- **上田総裁の見解**
  - 中東情勢の不透明性は、金融市場に影響を与える可能性があるが、日本経済の動向を優先的に判断すべきとの立場を示した。
  - 為替や資本動員の変動を踏まえながら、金融政策の柔軟性を確保する必要性を強調。

---

### **4. 次回の対応**
- 講演後の記者会見で、具体的な利上げの条件や時期についての発表は控えられるとの情報が伝えられた。
- 金融政策決定会合の結果については、翌日(16日)に発表予定。

---
**備考**:議事録作成日:令和X年X月X日

---
※ 日時・場所・出席者等の詳細は、実際の会議の記録をもとに修正が必要です。

(py313watchdog) PS C:\Users\rinsaka\Documents\python\watchdog>

ここまでで概ね全ての工程が終了しました.しかしながら,Windows で様々な音声ファイルの処理を行うと一部の音声ファイルで文字起こしに失敗することがあります.ある音声ファイルを監視フォルダに設置しました.フォルダ監視プログラムは問題なく動作します.

(py313watchdog) PS C:\Users\rinsaka\Documents\python\watchdog> python watch.py ⏎
[18:33:02.584715] 新しいファイルを検出: C:\Users\rinsaka\Documents\python\watchdog\watch\voice-sample-error.m4a
[18:33:02.584945] 新しいファイルの名前: voice-sample-error.m4a
[18:33:12.585767] ファイルの受取りが完了しました
[18:33:12.585902] ファイルの移動開始: C:\Users\rinsaka\Documents\python\watchdog\queue\voice-sample-error.m4a
[18:33:12.586496] ファイルの移動完了: C:\Users\rinsaka\Documents\python\watchdog\queue\voice-sample-error.m4a
Ctrl + C
[18:36:04.705437] 停止します
(py313watchdog) PS C:\Users\rinsaka\Documents\python\watchdog>

しかしながら,ワーカープログラムでは「WhisperXの処理に失敗しました」というメッセージが表示されました.

(py313watchdog) PS C:\Users\rinsaka\Documents\python\watchdog> python worker.py ⏎
[18:33:13.110558] ----------------
[18:33:13.110697] 処理開始: voice-sample-error.m4a
[18:33:13.111443] 作業開始: C:\Users\rinsaka\Documents\python\watchdog\working\voice-sample-error.m4a
[18:33:13.111508] 出力先 : C:\Users\rinsaka\Documents\python\watchdog\working\voice-sample-error
[18:33:13.111555] 文字起こし処理中...
[18:35:54.308259] WhisperXの処理に失敗しました
[18:35:54.310093] 失敗: C:\Users\rinsaka\Documents\python\watchdog\error\20261102-183554_voice-sample-error\voice-sample-error.m4a
Ctrl + C
[18:36:06.872781] 停止します
(py313watchdog) PS C:\Users\rinsaka\Documents\python\watchdog>

エラー用 error フォルダを確認します.その中に WhisperX のログファイルが存在します.そのログファイルにエラーの原因を探るヒントがあるはずです.

(py313watchdog) PS C:\Users\rinsaka\Documents\python\watchdog> gci error -Recurse ⏎

    ディレクトリ:C:\Users\rinsaka\Documents\python\watchdog\error

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d----          2026/11/02    18:35                20261102-183554_voice-sample-error

    ディレクトリ:C:\Users\rinsaka\Documents\python\watchdog\error\20261102-183554_voice-sample-error

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d----          2026/11/02    18:35                voice-sample-error
-a---          2026/10/26    14:29       39603955 voice-sample-error.m4a

    ディレクトリ:C:\Users\rinsaka\Documents\python\watchdog\error\20261102-183554_voice-sample-error\voice-sample-error

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d----          2026/11/02    18:33                voice-sample-error

    ディレクトリ:C:\Users\rinsaka\Documents\python\watchdog\error\20261102-183554_voice-sample-error\voice-sample-error\voice-sample-error

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a---          2026/11/02    18:35          35631 whisperx.log

(py313watchdog) PS C:\Users\rinsaka\Documents\python\watchdog>

ログファイルの中身を確認します.「�w�肳�ꂽ�v��」のように文字化けしている部分がありました.さらに下に進むと,「UnicodeEncodeError: 'cp932' codec can't encode character '\ufffd' in position 243: illegal multibyte sequence」という重要なメッセージが残されていました.

(py313watchdog) PS C:\Users\rinsaka\Documents\python\watchdog> Get-Content error\20261102-183554_voice-sample-error\voice-sample-error\voice-sample-error\whisperx.log ⏎
C:\Users\rinsaka\anaconda3\envs\py313watchdog\Lib\site-packages\pyannote\audio\core\io.py:48: UserWarning:
torchcodec is not installed correctly so built-in audio decoding will fail. Solutions are:
* use audio preloaded in-memory as a {'waveform': (channel, time) torch.Tensor, 'sample_rate': int} dictionary;
* fix torchcodec installation. Error message was:

[WinError 127] �w�肳�ꂽ�v���V�[�W����������܂���B
  warnings.warn(
2026-11-02 18:33:20 - whisperx.asr - INFO - Compute type not specified, defaulting to float16 for device cuda
2026-11-02 18:33:22 - whisperx.vads.pyannote - INFO - Performing voice activity detection using Pyannote...
Lightning automatically upgraded your loaded checkpoint from v1.5.4 to v2.6.6. To apply the upgrade to your files permanently, run `python -m lightning.pytorch.utilities.upgrade_checkpoint C:\Users\rinsaka\anaconda3\envs\py313watchdog\Lib\site-packages\whisperx\assets\pytorch_model.bin`
2026-11-02 18:33:24 - whisperx.transcribe - INFO - Performing transcription...
C:\Users\rinsaka\anaconda3\envs\py313watchdog\Lib\site-packages\pyannote\audio\utils\reproducibility.py:74: ReproducibilityWarning: TensorFloat-32 (TF32) has been disabled as it might lead to reproducibility issues and lower accuracy.
It can be re-enabled by calling
   >>> import torch
   >>> torch.backends.cuda.matmul.allow_tf32 = True
   >>> torch.backends.cudnn.allow_tf32 = True
See https://github.com/pyannote/pyannote-audio/issues/1370 for more details.

  warnings.warn(
Transcript: [24.871 --> 54.233] �{���͑�2��̐V�w�������ψ���Ɠ����ɓs��̕����J�×\�肵�Ă���܂���10��29���ؗj���̌����ψ����ɂ�����̓��e�ɂ��Ď��O�ɓ��e���m�F������œ����J�ÂƂ������Ƃŗ\�肵�����Ǝv���Ă���܂�
Transcript: [55.651 --> 85.064] ���e�Ȃ�ł�����ǂ��V�w�Z�����ψ���̑�2��̉ۑ�̕����������������ߋ��Ɍ���Љ�w���𗧂��グ���ۂ̎������Q�l�ɂ��Ȃ���܂��͐V�w�Z�����ψ���ŐV���Z������Ė�Ȋw��
...(中略)...
Transcript: [2387.523 --> 2412.802] ���N�̌��吶���������� 11��2������11��10���܂ŏo����Ԃ�����܂��āA11��13���� �u��Ҋm�肷��悤�ɂȂ��Ă��܂��B�ł��̂ŁA������x�A ���吶���������̏o��󋵂��A�����҂Ă�̂ł���΁A 11��13���Ɏu��҂��m�肵�܂��̂ŁATraceback (most recent call last):
  File "<frozen runpy>", line 203, in _run_module_as_main
  File "<frozen runpy>", line 88, in _run_code
  File "C:\Users\rinsaka\anaconda3\envs\py313watchdog\Scripts\whisperx.exe\__main__.py", line 5, in <module>
    sys.exit(cli())
             ~~~^^
  File "C:\Users\rinsaka\anaconda3\envs\py313watchdog\Lib\site-packages\whisperx\__main__.py", line 98, in cli
    transcribe_task(args, parser)
    ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^
  File "C:\Users\rinsaka\anaconda3\envs\py313watchdog\Lib\site-packages\whisperx\transcribe.py", line 151, in transcribe_task
    result: TranscriptionResult = model.transcribe(
                                  ~~~~~~~~~~~~~~~~^
        audio,
        ^^^^^^
    ...<3 lines>...
        verbose=verbose,
        ^^^^^^^^^^^^^^^^
    )
    ^
  File "C:\Users\rinsaka\anaconda3\envs\py313watchdog\Lib\site-packages\whisperx\asr.py", line 280, in transcribe
    print(f"Transcript: [{round(vad_segments[idx]['start'], 3)} --> {round(vad_segments[idx]['end'], 3)}] {text}")
    ~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
UnicodeEncodeError: 'cp932' codec can't encode character '\ufffd' in position 243: illegal multibyte sequence

Transcript: [2413.038 --> 2437.102] ���̎��_�ŁA���N�̓����̓������킩�邩�ȂƎv����ł����ǁA���ɖ�w���Ɋւ��ẮA�ł��S���I�Ȗ�w�����o���đ�w�̌X���ɂ͂Ȃ��ł����ǂ��A
...(中略)...
Transcript: [3165.022 --> 3183.196] �w�@�̐ݒ�Ƃ������Ƃł��ˁB�����ɂ��ẮA���������������Ă����ł��ˁB����1�ł��ˁB�w�@�Ɋւ��܂��ẮA������x�w�@�̐ݒ�A
(py313watchdog) PS C:\Users\rinsaka\Documents\python\watchdog>

これは Windows が内部では CP932 というコードページ(つまり Shift-JIS 文字コード)で処理していることが原因です.一方で macOS や Linux では発生しないと思われます.この問題を解決する1つの方法は,ワーカープログラムを実行する前にあらかじめ Python 実行環境で UTF-8 を利用するように指定するものです.

(py313watchdog) PS C:\Users\rinsaka\Documents\python\watchdog> $env:PYTHONIOENCODING="utf-8" ⏎
(py313watchdog) PS C:\Users\rinsaka\Documents\python\watchdog> python worker.py ⏎

なお,$env に関する説明はこちらを参照してください.その上で,毎回上のコマンドを実行すればよいのですが,実行し忘れると問題がまた発生する可能性があります.次のページでは Python コードの中で文字コードを指定するように修正します.

目次に戻る