やりたいこと
下記のようなエクセルファイル(data.xlsx)があったとします。
そこから、こういう形式のjsonファイル(output.json)をつくりたい。
ちなみに課題は、
- 日時(yyyy-mm-ddThh:mm形式)をjson書き出しのときに扱えないよとエラーが出る。
- 日本語が
\uXXXX
形式になってしまい、ちゃんと表示されない。 - 数式の場合、数式ではなく値を取得してきて欲しい。
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
"title": "芝浜",
"description": "芝の浜で拾った財布の中に大金が…。",
"timestamp": "2024-01-02T10:45"
}
},
{
"type": "Feature",
"properties": {
"title": "浜野矩随",
"description": "名人の息子も職人。だが全然うではよくなくて…。",
"timestamp": "2024-01-10T12:30"
}
},
{
"type": "Feature",
"properties": {
"title": "人情八百屋",
"description": "八百屋が困窮する家族に出会い、野菜やお金をわけてあげるが…。",
"timestamp": "2024-02-05T19:00"
}
}
]
最終的にこうなったよ
import openpyxl
import json
import pandas as pd
from datetime import date, datetime
###########jsonでdatetime型が扱えないので文字列に変換###########
# date, datetimeの変換関数
def json_serial(obj):
# 日付型の場合→文字列にする
if isinstance(obj, (datetime, date)):
return obj.strftime("%Y-%m-%dT%H:%M")
# 上記以外はサポート対象外.
raise TypeError ("Type %s not serializable" % type(obj))
# datetime型を含むdict
item = { "dt" : datetime.now() }
#################################################
# Excel ファイルを読み込む
workbook = openpyxl.load_workbook(r"C:\Users\hogehoge\Desktop\data.xlsx", data_only=True)
worksheet = workbook.active
# ワークシートのデータをリストに格納
data = []
for row in worksheet.iter_rows(values_only=True):
data.append(row)
# リストから DataFrame を作成
dataframe = pd.DataFrame(data, columns=data[0])
# 最初の行は列名なので削除
dataframe = dataframe.iloc[1:]
# DataFrame の各行のデータを取得し、JSON 形式のデータを生成する
features = []
for _, row in dataframe.iterrows():
feature = {
"type": "Feature",
"properties": {
"title": row["title"],
"description": row["description"],
"timestamp": row["timestamp"],
},
}
features.append(feature)
# JSON データを生成する
data = {
"type": "FeatureCollection",
"features": features
}
# JSON ファイルに出力する
output_file = r"C:\Users\hogehoge\Desktop\output.json"
with open(output_file, "w", encoding="utf-8") as jsonfile:
json.dump(data, jsonfile, indent=2, ensure_ascii=False, default=json_serial)
簡単に何をやったか解説していきます。
①datetimeの型を文字列にしてjsonが書き出せるようにする
早速、openpyxl,json,pandasを使って実行してみたものの、
TypeError: Object of type datetime is not JSON serializable
というエラーが出てしましました。
どうもモジュール jsonはdatetimeに対応してないよ、ということみたいです。
ので、下記のような箇所を加えて対策。
###########jsonでdatetime型が扱えないので文字列に変換###########
# date, datetimeの変換関数
def json_serial(obj):
# 日付型の場合→文字列にする
if isinstance(obj, (datetime, date)):
return obj.strftime("%Y-%m-%dT%H:%M")
# 上記以外はサポート対象外.
raise TypeError ("Type %s not serializable" % type(obj))
# datetime型を含むdict
item = { "dt" : datetime.now() }
#################################################
json.dump(data, jsonfile, indent=2, default=json_serial)
形式の調整したいときは、
“%Y-%m-%dT%H:%M”を”%Y-%m-%dT%H:%M:%S”にすれば、
2024-01-01T00:00:00
というように秒も出せそうですね。
※こちらのページを参考にさせて頂きました。
②jsonで日本語がうまく表示されない部分を解決
①を解決すると、jsonファイルは生成されるものの、こんな感じになります。
"title": "\u829d\u6d5c",
"description": "\u829d\u306e\u6d5c\u3067\u62fe\u3063\u305f\u8ca1\u5e03\u306e\u4e2d\u306b\u5927\u91d1\u304c\u2026\u3002"
でも、絶望しなくてOK!(←一時した人)
jsonの書き出しを指示する部分(json.dump)に、ensure_ascii=Falseというオプションを加えれば解決します。
json.dump(data, jsonfile, indent=2, ensure_ascii=False, default=json_serial)
※こちらのページを参考にさせて頂きました。
③Excelから取得するのは関数ではなく、値にして欲しい
最後です。たとえばExcelが関数を使用して値を出しているとき、値を取得して欲しいのに、関数をそのまま取得されてしまいます。
そんなときは、openpyxl.load_workbook()部分にオプション(data_only=True)を加えれば、関数ではなく値を取ってきてくれます。
workbook = openpyxl.load_workbook(r"C:\Users\hogehoge\Desktop\data.xlsx", data_only=True)
※こちらの記事を参考にさせて頂きました。
最後に
浜野矩随と芝浜は五代目円楽が好きです。人情八百屋は立川梅春(ビートたけし)のが意外によかったです。
コメント