Pythonの文字コード【コメント解決篇】

昨日の文字コードの件について、コメントを3件いただきました。コメントしたいただいたid:aodagさん、otsukaさん、ocean-cityさんありがとうございました。正直3件もコメントしていただけるとは予想していなかったので、びっくりしていますw。

ディフォルトエンコーディングの設定

id:aodagさんのコメントより。Vine Linuxでは/usr/lib/python2.4/site/packagesにsitecustomize.pyというファイルを作り、コメントにあった、

import sys, os
sys.setdefaultencoding(”utf-8”)

この設定をしたところ、昨日のプログラムで一番気になっていた、

f.write(tagName.find("a").string.encode("utf-8")+"\n")

の部分を

f.write(tagName.find("a").string+"\n")

とすることができました。これは気持ちがいい!!

otsukaさんのコメント

「data=unicode(data,’UTF-8’)」は入らないかも、ということでしたが、昨夜時点では、この記述がないと文字化けしてしまうため必要になっていました。しかし、上で行ったディフォルトエンコーディングの指定をしてからはこれがなくても動くようになりました!!

あと、「tagName.find(”a”).renderContents()だけでも大丈夫かも知れません。」とのことだったのでこっちでも試したところうまくいきました。が、stringとrenderContents()の使い分け(?)がよく分かりませんでした。この例だと同じ挙動を示したんですが、他の例だとどっちかしかいかないという状況が発生しうるのでしょうか?この辺とか見たら解決しそうな気がする。あとでもう少し詳しく調べてみるかもしれません。

追記

ちょっと分かりました。終わりのほうを参照してください。

マルチバイト文字の読み書き

ocean-cityさんのコメントによると、

一般的には、マルチバイト文字をファイルに書くには
f=open(”./hatebu.txt”,”w”)

import codecs
f=codecs.open(”./hatebu.txt”,”w”,”utf-8”)
にするといいと思います。

とのことでした。ん、codecsって知らないぞ…っていうことで少し調べてみました。以下のサイトが参考になりました。

なるほど、codecsというのを使うとファイルの読み書きのときに文字コードを指定することができるのですね。さっきのサイトに載っていた例だと

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import codecs
fout = codecs.open('sjis.txt', 'w', 'shift_jis')
for line in codecs.open('euc.txt', 'r', 'euc_jp'):
    fout.write(line)

とやることで、読み込むファイルはshift_jisで、書き込むときにはeuc_jpで、ということが可能になるということだと理解しました。

現時点での修正コード

とりあえず、昨夜のコードをコメントしてもらった付近をあわせて、修正してみました。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from BeautifulSoup import BeautifulSoup
from urllib2 import urlopen
import codecs
b=BeautifulSoup
f = urlopen("http://b.hatena.ne.jp/syou6162/python")
data=b(f.read())
f=codecs.open("./hatebu.txt","w","utf-8")
for tagName in data.findAll('dt'):
        if(tagName.attrs[0][1]=="bookmark"):
                f.write(tagName.find("a").attrs[0][1]+"\n")
                f.write(tagName.find("a").string+"\n")
                f.write(tagName.find("a").renderContents()+"\n")
                f.write(str(tagName.find("a"))+"\n")
                f.write(tagName.find("a").__str__()+"\n")
f.close()

stringとrenderContents()のところは少し分からないけど、とりあえずこれを元に少し何か作ってみます。コメントありがとうございました。

追記【stringとrenderContents()の違い】

stringとrenderContents()の違いがちょっと分かったのでメモとして書いときます。stringは取得してきた要素にもうタグのようなものが含まれなかったらrenderContents()と同じような働きをします。しかし、取得してきた要素が「<b>Python<b/>で文字コード」のようにhtmlタグが入っているとstringではNoneを返してしまうようです。otsukaさんが教えてくださったrenderContentes()のほうはタグを含んだ形で返してくれます。僕の使いかたではrenderContentes()のほうが何かとよさそうです。stringしか知らなかったらはまってるとこでしたw。otsukaさん、ありがとうございました!!