無料会員なら、交流会・掲示板・会員の道具が使えます。

無料登録 →
← 投稿一覧

SNSの自動投稿で日本語が文字化けした原因と防ぎ方

かつ

かつ

2026/09/29

自動投稿で日本語が文字化け。X・Threads・YouTubeに、原因はコマンド1行。再現して、投稿前に止める仕組みへ。右に、本文だけが化けたXの投稿の画面

SNSへの投稿を自動にしたら、日本語の本文が読めない記号の列になって公開されていました。2026年9月29日、Claude Sonnet 5.5の紹介動画をX・Threads・YouTubeに出したときのことです。動画はきれいに出ていて、文字だけが化けていました。

先に結論です。

  • 原因は、投稿文をコマンドに渡す1行でした。Windowsでは、Pythonがパイプに出す文字はShift_JIS系(cp932)になります。それをUTF-8のつもりで受け取ったため、化けました
  • SNS側はエラーを返しません。化けた本文もそのまま受け付けて公開します。画面を見るまで、誰も気づけませんでした
  • 防ぎ方は2つです。本文はコマンドの引数ではなくUTF-8のファイルで渡すこと。そして、送る前に「化けた文字が混ざっていないか」を機械で確かめ、混ざっていたら止めることです

何が起きたか

カツプロでは、記事を紹介する短い動画を作り、各SNSへの投稿をAI(Claude Code)に任せています。投稿には各社の公式APIを使っています。

この日、投稿から約5時間後に、Xの画面で本文が化けているのに気づきました。

Xの投稿。1行目の「Claude Sonnet 5.5」のあとが記号の列になり、箇条書きも読めない。下の動画は正常
Xに出た投稿。英数字と動画は正常で、日本語だけが化けている

調べると、同じ動画を出したThreadsの本文と、YouTubeの説明欄も化けていました。YouTubeは、題名だけが正常でした。題名はコマンドに直接書いていて、後で説明する「ファイルから取り出す」経路を通っていなかったためです。

Threadsの投稿。本文の日本語が「�」と記号の列になっている
Threadsの投稿(ログインしていないブラウザ・スマホの幅で表示)
YouTubeの動画ページ。題名は正常だが、説明欄の日本語が記号の列になっている
YouTubeは題名が正常で、説明欄だけが化けた

どの画面でも、英数字(Sonnet 5、30%、URLなど)とハッシュタグの英字は正しく出ています。化けたのは日本語だけです。これが原因を探す手がかりになりました。

原因:文字の「書き方」の取り違え

化けた文字から逆算する

XのAPIで化けた本文を取り直すと、先頭は次のようになっていました(2026年9月29日、カツプロ調べ)。

'Claude Sonnet 5.5 \x82ª\x8fo\x82܂µ\x82½\x81B'

「が」は、Shift_JIS系の文字コードcp932では 82 AA の2バイトで表します。「出」は 8F 6F です。上の文字列には、この2バイトが1バイトずつ別の文字として並んでいます。

そこで、化けた文字をバイトに戻し、cp932として読み直しました。すると「Claude Sonnet 5.5 が出ました。」に戻りました(カツプロ調べ)。日本語がcp932のバイトのまま、UTF-8のつもりで読まれていたことになります。

Threadsでは、化けた文字の一部が「�」(読めない文字の置き換え記号)で保存されていました。そのため、Xのように元の文へ戻すことはできませんでした。

問題の1行

投稿したときのコマンドを見返すと、原因はこの形でした。

TXT=$(python -c "print(投稿文.md から X の欄を取り出す)")
python xpost.py post "$TXT" --video 動画.mp4

1行目で、投稿文のファイルから本文を取り出して変数に入れます。2行目で、その変数を投稿の道具に渡します。

Pythonの公式ドキュメントには、Windowsでの出力の文字コードについてこう書かれています(Python ドキュメント「sys」の stdout の項)。

On Windows, UTF-8 is used for the console device. Non-character devices such as disk files and pipes use the system locale encoding (i.e. the ANSI codepage).

画面に出すときはUTF-8ですが、ファイルやパイプに出すときは、パソコンの地域設定の文字コードになるということです。日本語のWindowsでは、これがcp932です。手元のPython 3.11.4でパイプに出したときの文字コードを確かめると、cp932 と出ました(カツプロ調べ)。

1行目の $( … ) は、Pythonの出力をパイプで受け取ります。つまり本文は、cp932のバイトとして変数に入りました。2行目の投稿の道具は、それをUTF-8として受け取りました。ここで化けています。

手元で再現した

同じ形のコマンドを、投稿しない形で手元で試しました(2026年9月29日、Windows 11・Git Bash・Python 3.11.4、カツプロ調べ)。

TXT=$(python -c "print('Claude Sonnet 5.5 が出ました。')")
python -X utf8 -c "import sys; print(repr(sys.argv[1]))" "$TXT"
→ 'Claude Sonnet 5.5 \x82ª\x8fo\x82܂µ\x82½\x81B'

Xに出たものと、1文字も違わない化け方になりました。取り出す側に文字コードを指定すると、化けませんでした。

TXT=$(PYTHONIOENCODING=utf-8 python -c "print('Claude Sonnet 5.5 が出ました。')")
→ 'Claude Sonnet 5.5 が出ました。'

実は、投稿の道具を動かす2行目には、この PYTHONIOENCODING=utf-8 を付けていました。付け忘れていたのは、本文を取り出す1行目のほうでした。

どう直したか

直し方は、SNSごとに違いました。

SNS直し方
X正しい本文で動画ごと出し直し、化けた投稿はAPIで削除した
Threads正しい本文で出し直した。化けた投稿の削除はAPIで断られ、手で消した
YouTube動画はそのままにして、説明欄だけをAPIで書き換えた

Threadsの投稿をAPIで消すには、threads_delete という権限が要ります(Threads API「Delete Posts」)。つないだときにこの権限をもらっていなかったため、「このアプリには権限がない」というエラーで断られました。

YouTubeの説明欄はAPIで書き換えられます。ただし公式ドキュメントに、指定しなかった項目は消えるという注意があります(YouTube Data API「Videos: update」)。

If you are submitting an update request, and your request does not specify a value for a property that already has a value, the property's existing value will be deleted.

説明欄だけを送ると、題名やタグが消えてしまいます。そこで、いまの題名・カテゴリ・タグを読み出してから、説明欄だけを差し替えて送りました。

出し直したThreadsの投稿。「Claude Sonnet 5.5 が出ました。」から始まる本文が正しく表示されている
出し直したThreadsの投稿
YouTubeの説明欄。「2026年9月28日、AnthropicがClaude Sonnet 5.5を発表しました。」から始まる文が正しく表示されている
書き換えたYouTubeの説明欄

同じことを起こさないために

1. 本文はファイルで渡す

日本語の本文を、コマンドの引数で渡すのをやめました。投稿の道具に「UTF-8のファイルから本文を読む」指定を足し、そちらを使います。

python xpost.py post --text-file X本文.txt --video 動画.mp4

ファイルを読むときに文字コードをUTF-8と決めておけば、途中でパイプや変数を通らないので、取り違えが起きません。

2. 送る前に機械で確かめ、化けていたら止める

X・Threads・YouTubeの3つの投稿の道具すべてに、送る直前の確認を入れました。本文に次の文字が1つでもあれば、投稿せずに止まります。

  • U+0080〜U+009F の文字:ふつうの文章には出てこない制御用の文字です。今回の化け方では、ほぼ必ず混ざります
  • 「�」(U+FFFD):読めなかった文字の置き換え記号です。Threadsで保存されていたものです

今回の化けた本文をそのまま渡して試すと、投稿せずに止まりました(カツプロ調べ)。

この確認は、今回と同じ種類の化け方を止めるためのものです。別の種類の化け方(たとえばUTF-8をcp932として読んだ「縺」のような漢字の列)は、この確認では止まりません。

3. Pythonの設定で、そもそもUTF-8にする

Pythonには、入出力をUTF-8にそろえる「UTF-8モード」があります。起動時の -X utf8 か、環境変数 PYTHONUTF8 でオンにできます。前に出た PYTHONIOENCODING も同じく、出力の文字コードを変える環境変数です(Python ドキュメント「sys」)。

UTF-8モードは、Python 3.15で最初からオンになります(PEP 686「Make UTF-8 mode default」)。ただし、3.14以前のPythonで動いている道具は、いまも今回と同じ化け方をします。

小さな会社・Web制作者にはどう効くか

今回いちばん困ったのは、化けたことより、約5時間だれも気づかなかったことです。SNSのAPIは、化けた本文を正しい投稿として受け付けます。エラーも警告も出ません。YouTubeの化けた説明欄は、見に行った時点で27回見られていました。

SNSの自動投稿やAIへの作業の丸投げは、手間を大きく減らしてくれます。その代わり、「送ったら終わり」になりやすく、人の目が入る場所がなくなります。

自動にするなら、次の2つをセットで入れておくのがおすすめです。

  • 送る前の確認を、道具の中に入れる。人やAIが毎回気をつけるのではなく、化けていたら道具が止まる形にします
  • 日本語は、ファイルで受け渡す。特にWindowsでは、コマンドの引数や $( … ) で日本語を運ばないようにします

WordPressのプラグインや業務の自動化でも、Windowsで動かすPythonのスクリプトが日本語を扱う場面は多いはずです。一度、日本語がどこを通っているかを見直してみてください。

この記事の著者・監修

カツ
生成AIエンジニア/フロントエンドエンジニア/舞台監督などなど

カツ

カツプロ運営者のカツです! AI・Web関連から、日常のことなど、私目線の回答も交えながらお伝えします!

この記事をシェア

note

スポンサーリンク

コメント(0)

まだコメントはありません。

コメントは Tier 1(有料)の機能です。ログインのうえアップグレードしてください。

こちらの記事も読まれています