質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.47%
スクレイピング

スクレイピングとは、公開されているWebサイトからページ内の情報を抽出する技術です。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

文字コード

文字コードとは、文字や記号をコンピュータ上で使用するために用いられるバイト表現を指します。

Q&A

解決済

1回答

3130閲覧

Unicodeエスケープシーケンスを変換したい

34Noe

総合スコア3

スクレイピング

スクレイピングとは、公開されているWebサイトからページ内の情報を抽出する技術です。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

文字コード

文字コードとは、文字や記号をコンピュータ上で使用するために用いられるバイト表現を指します。

0グッド

1クリップ

投稿2022/04/01 07:20

編集2022/04/01 08:40

実現したいこと

取得した文字列をデコードしたい。

生じている問題

スクレイピングによって取得した文字列がUnicodeエスケープシーケンスで記述されており、これをデコードするためのコードを実行したところエラーが表示されました。

当該のソースコード

Python3.10.1

1mport stweet as st 2 3def try_serch(): 4 5search_tweets_task = st.SearchTweetsTask(all_words = "検索ワード") 6output_jl_tweets = st.JsonLineFileRawOutput('data.txt') 7output_print = st.PrintRawOutput() 8 9st.TweetSearchRunner(search_tweets_task=search_tweets_task, 10tweet_raw_data_outputs=[output_print, output_jl_tweets], 11user_raw_data_outputs=[]).run() 12 13if __name__ == "__main__": 14try_serch() 15

Python3.10.1

1source = open('data.txt','r') 2out = open('data_decoded.txt','w') 3 4for row in source: 5 new = row.encode().decode('unicode-escape') 6 out.write(new) 7 8source.close() 9out.close()

エラー

utf-8変換前

Traceback (most recent call last): File "c:\VSCode\Source\Python\Scraping\Encoder.py", line 6, in <module> out.write(new) UnicodeEncodeError: 'cp932' codec can't encode character '\ud83d' in position 266: illegal multibyte sequence

変換後

Traceback (most recent call last): File "c:\VSCode\Source\Python\Scraping\Encoder.py", line 6, in <module> out.write(new) UnicodeEncodeError: 'utf-8' codec can't encode characters in position 266-267: surrogates not allowed

作成されたテキストファイルの変換したい部分

"full_text" : "\u3053\u308C\u306F\u30C6\u30B9\u30C8"

このような記述がされており、その一部分である\ud83dが引っかかったようです。

特に分からないこと

utf-8とcp932の食い違いであるということは記事を読んで理解できました。そのためファイルの読み書き時にutf-8でコーディングを行ってみましたが上手く動きません。どこを見落としているのでしょうか?

Python

1source = open('data.txt','r',encoding='utf-8') 2out = open('data_decoded.txt','w',encoding='utf-8')

至らない点が多々あると思いますが、ご回答よろしくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

quickquip

2022/04/01 07:33

Tracebackがないのでどこでエラーがでたのかわかりません。 utf-8にした場合も「上手く動きません」とだけあって何が起こったのかわかりません。 今Pythonを使ってファイル開けていない状態で、「Unicodeエスケープシーケンスで記述されて」いると思ったのはなぜか(なにを使ってどうなったからそう判断したのか)もあるとよいと思います。 結果から考えると単純に「そのファイルはテキストではない」可能性が高そうなのですが、ファイルはどのようにして作られたのでしょうか?
34Noe

2022/04/01 07:48

情報不足で申し訳ありません。 テキストファイルを作成するのはstweetを使用した以下のコードなのですが、 import stweet as st def try_serch(): search_tweets_task = st.SearchTweetsTask(all_words = "検索ワード") output_jl_tweets = st.JsonLineFileRawOutput('data.txt') output_print = st.PrintRawOutput() st.TweetSearchRunner(search_tweets_task=search_tweets_task, tweet_raw_data_outputs=[output_print, output_jl_tweets], user_raw_data_outputs=[]).run() if __name__ == "__main__": try_serch() これによって作成されたファイルdata.txtを確認すると検索ワードに引っかかった文字列が、Unicodeエスケープシーケンスでテキストファイル内に記述されていたためそう判断しました。 またutf-8に変換前は Traceback (most recent call last): File "c:\VSCode\Source\Python\Scraping\Encoder.py", line 6, in <module> out.write(new) UnicodeEncodeError: 'cp932' codec can't encode character '\ud83d' in position 266: illegal multibyte sequence 返還後は Traceback (most recent call last): File "c:\VSCode\Source\Python\Scraping\Encoder.py", line 6, in <module> out.write(new) UnicodeEncodeError: 'utf-8' codec can't encode characters in position 266-267: surrogates not allowed となりました。
quickquip

2022/04/01 08:22 編集

情報はこの欄ではなくて質問を編集して追記してください。 > これによって作成されたファイルdata.txtを確認すると検索ワードに引っかかった文字列が、Unicodeエスケープシーケンスでテキストファイル内に記述されていたため テキストエディタで見ると全部ASCIIの範囲の文字になっていて、中に \ud83d という文字列が見えるということで合ってますか。 追記: \ud83d は今エラーになっている部分で、これを検索すると本当にそこにあるのかと思って書きました。
34Noe

2022/04/01 08:43

編集した部分のような文字列が表示され、その中に\ud83dという文字列が含まれていました。
guest

回答1

0

ベストアンサー

>>> '🙏' '🙏' >>> len('🙏') 1

という顔文字があります。長さ1の文字列ですね。

>>> '🙏'.encode('unicode-escape') b'\\U0001f64f'

コードポイントはU+U0001f64f で、16ビットの範囲を超えている、Unicodeの追加漢字面に属する文字です。

>>> '🙏'.encode('utf-16-be') b'\xd8=\xdeO'

これをUTF-16で表現すると4バイトになります。UTF-16に追加されたサロゲートペアを使った符号化がされます。
もうちょっと見やすくしましょう。

>>> ' '.join(map(lambda x: hex(x)[2:], '🙏'.encode('utf-16-be'))) 'd8 3d de 4f'

d8 3d が表れました。今エラーになっている原因のUnicodeエスケープ表現はサロゲートペアのかたわれの部分なのです。

>>> '\ud83d\ude4f' '\ud83d\ude4f' >>> len('\ud83d\ude4f') 2 >>> b'\\ud83d\\ude4f'.decode('unicode-escape') == '\ud83d\ude4f' True >>> '\ud83d\ude4f' == '🙏' False

間違って(?)表現されたb'\\ud83d\\ude4f' というバイト列(テキストエディタで\ud83d\ude4fと見える部分)を、unicode-escapeでdecodeすると、長さ2の文字列になります。元々表現しようとしていた文字列とも別のものです。
これはサロゲートペアを別々に扱ったみたいな形になっていて、つまり不正なシークエンスです。

>>> '\ud83d\ude4f'.encode('cp932') Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeEncodeError: 'cp932' codec can't encode character '\ud83d' in position 0: illegal multibyte sequence 'cp932' codec can't encode character '\ud83d' in position 0: illegal multibyte sequence >>> '\ud83d\ude4f'.encode('utf-8') Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeEncodeError: 'utf-8' codec can't encode characters in position 0-1: surrogates not allowed 'utf-8' codec can't encode characters in position 0-1: surrogates not allowed

だから、cp932に原理的にencodeできない(=illegal multibyte sequence)だけでなく、UTF-8にもencodeできません(=surrogates not allowed)。

>>> '\ud83d\ude4f'.encode('utf-16', 'surrogatepass').decode('utf-16') '🙏'

"サロゲートペアのかたわれを拒絶しない"ハンドラ付きutf-16でencodeして、decodeするというイディオムがあるようです。
これで回避するか、encode時にerrors='ignore'指定してエラーを全部無視するとかで対応することになるでしょうか。

投稿2022/04/02 03:54

編集2022/04/02 03:55
quickquip

総合スコア11055

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

34Noe

2022/04/02 04:17

ご丁寧にありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問