いつものごとくスクレイプの話ですが、requestsを使っていて文字化けに少々ハマりましたので、残しておきます。
結果的にそもそも文字コードの扱いについてちゃんと理解できていなかったことが問題でしたー
HTMLのcharset
今回スクレイプしようとしていたWebサイトはmetaタグのcharsetにEUC-JP
が設定されていました
requestsさんですが、基本的にはmetaタグではなくHTTPレスポンスヘッダのcontent-typeをみてcharsetを判断しているようです。が、content-typeが対象のWebで設定されておらず読めない場合はデフォルトのISO-8859-1
となってしまうようです
result = requests.get('スクレイプするURL') print(result.encoding)
実行結果 ISO-8859-1
ちょっとググったら以下のやり方でうまいことエンコーディングしてくれる、という記事が見つかったりもしたのですが、今回はうまくいきませんでした。
result = requests.get('スクレイプするURL') result.encoding = result.apparent_encoding print(result.encoding)
実行結果 Windows-1252
ぬぬぬ・・・試してみたところWindows-1252
と判定されてしまいました( ´・ω・`)
reqeustsの中でchardet
を使って自動判定しているようなのですが、完璧ではないのだろうと思われます。当然、print(result.text)
の結果も文字化けしてしまっています
イラっときたので、直接ぶちこみました
result = requests.get('スクレイプするURL') result.encoding = 'EUC-JP' print(result.encoding)
実行結果 EUC-JP
文字化けも解消したので万事解決です(*´∀`*)
そもそもの理解不足について
上記までの説明でおっけーという方はページを閉じて頂いて構いません!
今回の問題を解決するにあたって少々ハマってしまったのは、文字コードに対する理解が浅かったためです(まだまだ足りてませんが・・)
文字化け
python3でstr型はUnicode形式です、また.encode()
を使って特定の形式にエンコードしたbytes型に変換することもできます
str = 'あ' print(str) # あ print(type(str)) # class 'str' print(str.encode('utf-8')) # b'\xe3\x81\x82' print(type(str.encode('utf-8'))) # class 'bytes'
つまりはstr型とbytes型は特定のエンコーディング形式で互いを行き来するのみになります
ここでなぜか私はresult.text
で得られるstr型をutf-8でencodeしようとしてみたり、そっからEUC-JPでdecodeしようとしてみたりとトンチンカンなことをやってしまっていました・・・(utf-8でencodeしたならば、当然utf-8でdecodeしなければなりません)
文字化けしてるEUC-JPをなんとかしてUTF-8に変換したい~みたいな思いがあったような気がしますが、Unicodeのstr型の時点で文字化けしていたので、どうもしようもありませんでした・・・
問題は入り口の時点で正しいエンコーディングで読めていなかったことだったのです(*´・∀・)