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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Python 3.x

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

Q&A

解決済

2回答

6418閲覧

python3, 表現できないユニコードを一部無視して処理したい

namnium1125

総合スコア2043

Python 3.x

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

0グッド

2クリップ

投稿2017/08/29 09:24

編集2017/09/04 04:03

初利用、初心者です。よろしくお願いします。

python3とseleniumを使ってwebサイトをスクレイピングしていました。

ユニコード文字列をlxml.htmlで取って来た要素に対して、

lang

1 comments = u"" 2 comments_elem = root.xpath('//li[@class="hoge"]/span') 3 for i,comment_elem in enumerate(comments_elem): 4 comments += comment_elem.text_content()

みたいな感じで抜き出していたのですが、

途中に絵文字等が入っていたらしく、

lang

1UnicodeEncodeError: 'UCS-2' codec can't encode characters in position 3898-3898: Non-BMP character not supported in Tk

というエラーが出てきました。

絵文字は不要なので、飛ばして続きの文字列を処理したいのですが、
どうすればいいのでしょうか?

###試したこと
下記サイトにStreamWriterを作ると良いみたいなことが書かれていたので
実践したのですが、
http://d.hatena.ne.jp/nishiohirokazu/20120112/1326355987

新たに

lang

1.... 2File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/codecs.py", line 377, in write 3 self.stream.write(data) 4TypeError: must be str, not bytes

というエラーが発生しました。dataがbyte列なのでstrに変えろということでしょうか?

よくわからないでやっているので、もしできればStreamWriterなどについても教えていただけると幸いです。

###補足情報
python3はver3.6.2
環境はmac OS X 10.9.5です。
容量の関係で更新できずosは若干古いですが、
本題とはあまり関係ないと思ってます。

回答よろしくお願いします。m(_ _)m

###追記

ご指摘を受けました
自己解決欄に書いたprint関数の部分について、です。

と言っても

lang

1comments = u"絵文字など????" # 実際のcommentsの中身は上記のコードでの結果 2 3print(comments)

といった程度のことです。

ただしどんな絵文字が上記のエラー原因になった(Non-bmpな絵文字と言われた)かは確認できていません。

自己解決欄に書いたコードに対しその解決方法(.translate等)が適用されていなかったと考えて下さい。

その他の部分で直接この件に関係するものはおそらくないです。

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

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

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

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

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

guest

回答2

0

ベストアンサー

ただdict型non_bmp_mapが何者なのかいまいちわかっていないので、もし出来れば教えていただきたいです。m(_ _)m

端的に言えば、

Unicodeの第1面のはじめのコードポイントからpythonが扱える最大のコードポイントまでを、
第0面の代替文字U+FFFDのコードポイントにすべてマッピングしたdict

です。

すこしシンプルすぎる回答なので、
問題の整理とともに、そもそもなぜこのようなことをしているのか説明したいと思います。

1. 問題の所在

まず、Unicodeには面(Plane)があることはご存知ですか?
日常的に使う文字のうち大部分は第0面(BMPとも呼ばれる)に存在しますが、
絵文字はUnicodeでは一部、第1面以降に属します。

ところで、質問文中のエラーメッセージにはUCS-2というエンコーディング方式^1がでてきますが、UCS-2はBMPしか扱えません。
つまり、今回のエラーは、第1面以降に属するUnicodeを、第0面しか扱えないUCS-2で処理しようとしたから発生したと考えられます。

2. 解決策

このエラーを解消するにはどうしたらよいでしょうか?

提示されたリンク先の回答者であるMartijn Pietersさんは、
エラー元の文字列(Unicode)に対して第一面以降に属するUnicodeを、
第0面に属する適当なUnicode(今回は代替文字であるU+FFFDを使った)に置換することで解決しようとしました。
Pythonで扱える以上のUnicodeは変換対象とする意味はないので、変換範囲は第1面の最初のUnicodeのコードポイントから
Pythonで扱える最大のUnicodeのコードポイント(sys.maxunicodeで得られる)に限定しています。

またこうした変換を実際に行うため、Martijn Pietersさんはコードポイント^2を文字列置換に利用するtranslate関数を使っています。
この関数は {'変換対象のUnicodeのコードポイント':'変換先のUnicodeのコードポイント'}となるdictを引数に渡して使用するもので、
例えば、第1面に属するU+1F44Dを代替文字U+FFFDに変換するには、

# -- python3系を前提とする -- # BMP外に属するUnicodeを含んだstr型の文字列 s = '\U0001F44D' # 組み込み関数ord()はUnicodeをコードポイントに変換する関数 non_bmp_map = { ord('\U0001F44D'): ord('\U0000FFFD')} # 変換された文字列を出力 print(s.translate(non_bmp_map))

のようにします。

3. まとめ

以上から、non_bmp_mapは、上述した問題を解消するために用意された

UCS-2が扱えないUnicode(すなわちBMP以外のUnicode)のコードポイントを
UCS-2でも扱えるUnicode(今回は代替文字U+FFFD)のコードポイントに置き換えるためのdict

であるということがわかります。

投稿2017/09/04 06:02

編集2017/09/06 18:30
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

namnium1125

2017/09/04 06:52

とてもわかりやすかったです。 回答ありがとうございました。m(_ _)m どうでもいいことですが、�ではなく、〓を表示したければ、non_bmp_map作成用dict.fromkeysの第2引数を0x3013にすればよい、という感覚でいいのでしょうか?
退会済みユーザー

退会済みユーザー

2017/09/04 07:31

> どうでもいいことですが、�ではなく、〓を表示したければ、non_bmp_map作成用dict.fromkeysの第2引数を0x3013にすればよい、という感覚でいいのでしょうか? そういう感覚でよいと思います。
namnium1125

2017/09/04 07:41

改めてありがとうございました。m(_ _)m
guest

0

エラーはprint関数で発生していたんですね(^ ^;
エラーの内容を少し勘違いしていたみたいです。

調べていたところ、下記質問サイトの回答従ったところうまくいきました。

https://stackoverflow.com/questions/32442608/ucs-2-codec-cant-encode-characters-in-position-1050-1050

lang

1import sys 2 3#hogeに絵文字入り文字列 4 5non_bmp_map = dict.fromkeys(range(0x10000, sys.maxunicode + 1), 0xfffd) 6print(hoge.translate(non_bmp_map)) 7

これで絵文字のところが?扱いになり、print関数でうまく出力することができました。

ただdict型non_bmp_mapが何者なのかいまいちわかっていないので、もし出来れば教えていただきたいです。m(_ _)m

投稿2017/08/30 07:47

編集2017/09/04 03:28
namnium1125

総合スコア2043

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

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

退会済みユーザー

退会済みユーザー

2017/09/04 02:29

本来訂正欄に書くべきことですが、訂正欄は可読性に著しく欠けるのでこちらに書かせていただきます。 エラーがprint関数で発生していることがわかったとおっしゃっていますが、 そうであるならば、そのprint関数を使った部分もこの質問で提示されているコードに含めるべきだと思います。 提示されたコード内では、内部的にもprint関数を呼び出しているようには読めないので、 きっとこのコードの下にprint関数を使った処理があるんですよね?
namnium1125

2017/09/04 03:58

コメントありがとうございます。m(_ _)m 質問の方に追記いたしました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問