MySQLが出力するCSVファイルをPythonで読みたい件 

はてなブックマーク - MySQLが出力するCSVファイルをPythonで読みたい件
Bookmark this on Delicious

ケースとしてはレアな気がしますが、MySQLのSELECT 〜 INTO OUTFILEで出力したCSVに対して、処理をしたい時があります。僕の場合はpythonでやるわけですが、MySQLが出力するCSVの形式がpythonデフォルトの物と違うようでハマったのでメモしておきます。

MySQLには以下のようにデータを入れておきます。JSON形式のテキストを1レコードのみ準備しています。

#!/usr/bin/python
# -*- coding: utf-8 -*-
 
import MySQLdb
import simplejson as json
 
def main():
  data = ['あ', 'い', 'う']
  cur = MySQLdb.connect(host='localhost', db='dbname', user='user', passwd='pass').cursor()
  if not cur.execute('SELECT * FROM csv_test'):
    cur.execute('INSERT INTO csv_test(json) VALUES(%s)', (json_data))
 
if __name__ == '__main__': main()

このデータをSQLでCSVに吐き出します。注意したいのはターミネータにタブを指定している事です。カンマがJSONデータに含まれている為か、後でパースする時に、デフォルトのままだと正常にパースされません。

SELECT title, json FROM csv_test LIMIT 2 INTO OUTFILE '/tmp/test.csv' FIELDS TERMINATED BY '\t';

するとCSVファイルの内容は以下のようになります。2列目がunicode表現になっています。これから元の文字列を含んだjsonを復元したいんですが、unicode表現のまま復元されてしまいハマりました。

テストデータ	["\\u3042", "\\u3044", "\\u3046"]

結論を書くとこのデータをパースするには以下のようにします。ポイントはCSVファイルの形式にあわせて、csv.Dialectのサブクラスを作ってパース時に指定する事です。Dialect使わずに、CSVファイル側を微調整しようとしても巧く行きませんでした(CSVの仕様を完全に把握してたら出来るんだと思います。)。また、escapecharacterを指定しないとスラッシュがunescapeされずにjsonデータを復元できません。

#!/usr/bin/python
# -*- coding: utf-8 -*-
 
import csv
import simplejson as json
from prettyprint import pp
 
class MySQLQuote(csv.Dialect):
  delimiter      = '\t'
  quotechar      = '\\'
  lineterminator = '\r\n'
  quoting        = csv.QUOTE_ALL
  escapechar     = '\\'
 
def main():
  reader = csv.reader(open('test.csv', 'rb'), MySQLQuote())
  for line in reader:
    pp(json.loads(line[1]))
 
if __name__ == '__main__':
  main()

僕はGAEを使っているので、データのアップロード時に使うCSVをこれで処理しています。

関連する記事

タグ: , ,

コメントをどうぞ