python3でjsonファイルをCSVに変換・出力する方法

# python3でjsonファイルを読み込んでCSV形式に変換・出力する方法
## 概要
jsonファイルを読み込んでCSV形式に変換・出力する方法。
実際に利用したシーンとしては、Trello上のタスクをgoogle spreadsheetに移行するというタスクが発生した時にさくっと書いたものです。
なので、今回はTrelloからExportしたjsonファイルを元に実装します。

## 開発環境
- MacOS
- python 3.4.3

## 手順
1. 取り出すデータを決める
2. jsonの中身を確認
3. 実装

## 取り出すデータを決める
そもそも何のデータを取り出す必要があるのかを決めます。
今回は以下のデータをTrelloから取り出すことにします。

| 項目名 | 値例 |
|:------|:----------|
|リスト名|"進行中"、"ToDo"|
|カード名|"Viewリファクタリング"|
|説明|"View部分のリファクタリングを進めます"|
|担当者|"hanako.yamada"|
|更新日時|"2017-09-15T11:30:46.376Z"|

## jsonの中身を確認
欲しいデータが決まったところでTrelloからエクスポートできるjsonを見てみましょう。

```json

{   //board情報
    "id": "59b435arfaersgf686c2de62eb9",
    "name": "board_name",
    "desc": "",
    "descData": null,
    "closed": false,
    ...//board情報が続く
    "actions": [ //チケット更新情報、今回は使用しない。
        {
            "id": "59b435arfaersgf686c2de62eb9",
            "idMemberCreator": "59b435arfaersgf686c2de62eb9",
            "data": {
                "list": {
                    "name": "着手中",
                    "id": "59b64966caad5d9c7237c292"
                },
                ...//各チケットの更新内容が続く
            },
    ],
    "cards": [ //★今回欲しいカード情報、ここから抽出する
        {
            "id": "59b435arfaersgf686c2de62eb9",
            "checkItemStates": null,
            "closed": true, //アーカイブされているカードはtrueになってる。
            "dateLastActivity": "2017-09-12T01:11:42.261Z", //更新日時
            "desc": "", //説明
            "descData": null,
            "idBoard": "59b435arfaersgf686c2de62eb9",
            "idList": "59b435arfaersgf686c2de62eb9", // リストID
            "idMembersVoted": [],
            "idShort": 73,
            "idAttachmentCover": null,
            "limits": {
            },
            "idLabels": [],
            "manualCoverAttachment": false,
            "name": "Viewリファクタリング", //カード名
            "pos": 15fa327,
            "shortLink": "4or037I",
            "badges": {
            },
            "dueComplete": false,
            "due": null,
            "idChecklists": [],
            "idMembers": [
                "59b75b3254eg6a0a535a2"  //メンバーID、今回は担当者の概念
            ],
            ...
        },
   ],
   "members": [ //メンバー情報
        {
            "id": "sjfhkaefi738jfrhoiehu", //ID
            "avatarHash": "c33cagagecd767a5ae882a5eef5",
            "bio": "",
            "bioData": null,
            "confirmed": true,
            "fullName": "hanako.yamada", //名前
            "idPremOrgsAdmin": [],
            "initials": "HY",
            "memberType": "normal",
            "products": [],
            "status": "disconnected",
            "url": "https://trello.com/hanakoyamada",
            "username": "hanako.yamada"
        },
    ],
    "lists": [ //リスト情報
        {
            "id": "59b643f2e948122d702be91f", //リストID
            "name": "ToDo", //リスト名
            "closed": false,
            "idBoard": "59ac257d5d0719548db78007",
            "pos": 32767.5,
            "subscribed": false,
            "limits": {
                "cards": {
                    "openPerList": {
                        "status": "ok",
                        "disableAt": 4750,
                        "warnAt": 4500
                    },
                    "totalPerList": {
                        "status": "ok",
                        "disableAt": 950000,
                        "warnAt": 900000
                    }
                }
            }
        },
        ...
     ],
}
```

jsonを見たところ欲しい情報は取れそうなことがわかった。
ただし、担当者（Trelloのメンバー情報）とリスト名は、"members"・"lists"を使って名前を出す工夫が必要。

## 実装
### 1. ローカルにあるjsonファイルを読み込む。

```py3
import sys

# Load Json File from ComandLine argument
#
with open(sys.argv[1], 'r') as f:
	data = json.load(f)
```
#### ファイル読み込み
sys.argvで、コマンドライン引数を取り出す事ができます。
例えば、```$ python example.py 1```とターミナルで打った場合は、
sys.argvの中身は、```["example.py", 1]```となります。
今回は、
```$ python xxx.py xxx.json```
でjsonファイルを指定する方式にします。

#### jsonファイルをロードして辞書型に変換

``` json.load() ```を使うことでjsonファイルを扱いやすい辞書型に変換してくれます。

### 2. 値抽出
辞書型に変換したデータから必要な値を取得していきます。
#### 担当者・リスト名取得
担当者（Trelloのメンバー情報）とリスト名を取得します。
これはカード情報（"cards"）内にあるIDから名前を逆引きする際の辞書として定義します。

```py3
# 
# Set members Dictionary
# 
members = {}
for member in data['members']:
	member_id = member['id']
	member_name = member['fullName']
	members.update({member_id: member_name})

#
# Set lists Dictionary
#
lists = {}
for list in data['lists']:
	list_id = list['id']
	list_name = list['name']
	lists.update({list_id: list_name})
```

#### カード情報を取り出す。
カード情報はcards配下のデータに対してループ処理を行います。

```py3
#
#  Get cards value
#
tickets = [] #後ほどCSVに書き込む値を格納するための配列
for card in data['cards']:
	closed = card['closed']
	if (closed == False): #アーカイブされていない生きているカードのみ取得
		updated_date = card['dateLastActivity']
		desc = card['desc']
		card_id = card['id']
		title = card['name']
		asigned_member_ids = card['idMembers']
		list_id = card['idList']

		# asigned_member_name
		if len(asigned_member_ids) > 0:
			asigned_member_id = asigned_member_ids[0] #カードに対して1メンバーのみ紐付いている前提です。
			asigned_member_name = members[asigned_member_id]
		else:
			asigned_member_name = ""

		# list_name
		list_name = lists[list_id]

		tickets.append([list_name, title, desc, asigned_member_name, updated_date])
```

### 3. CSV書き込み
抽出した値をCSVに書き込んでいきます。

```py3
import csv

#
# Write CSV
#
with open('trello_cards.csv', 'w', newline='') as csvFile:
    csvwriter = csv.writer(csvFile, delimiter=',',quotechar='"', quoting=csv.QUOTE_NONNUMERIC)
    csvwriter.writerow(['リスト名', 'カード名', '説明', '担当者', '更新日時'])
    for ticket in tickets:
        csvwriter.writerow(ticket)
```

以上で完成です・・・！
ターミナル上で、```$ python script名 Trelloからexportしたjson```を叩けば実行できます。

実行結果

```csv
"リスト名","カード名","説明","担当者","更新日時"
"ToDo","Viewリファクタリング","View部分のリファクタリングを進めます","hanako.yamada","2017-09-15T11:30:46.376Z"
...
```

最後に、ソースコード全量を以下に載せておきます。

```py3
#! /usr/bin/env python
# coding: utf-8

import sys
import json
import csv


#
# Load Json File from ComandLine argument
#
with open(sys.argv[1], 'r') as f:
	data = json.load(f)

# 
# Set members Dictionary
# 
members = {}
for member in data['members']:
	member_id = member['id']
	member_name = member['fullName']
	members.update({member_id: member_name})

#
# Set lists Dictionary
#
lists = {}
for list in data['lists']:
	list_id = list['id']
	list_name = list['name']
	lists.update({list_id: list_name})

#
#  Get cards value
#
tickets = []
for card in data['cards']:
	closed = card['closed']
	if (closed == False):
		updated_date = card['dateLastActivity']
		desc = card['desc']
		card_id = card['id']
		title = card['name']
		asigned_member_ids = card['idMembers']
		list_id = card['idList']

		# asigned_member_name
		if len(asigned_member_ids) > 0:
			asigned_member_id = asigned_member_ids[0]
			asigned_member_name = members[asigned_member_id]
		else:
			asigned_member_name = ""

		# list_name
		list_name = lists[list_id]

		tickets.append([list_name, title, desc, asigned_member_name, updated_date])


#
# Write CSV
#
with open('trello_cards.csv', 'w', newline='') as csvFile:
	csvwriter = csv.writer(csvFile, delimiter=',',quotechar='"', quoting=csv.QUOTE_NONNUMERIC)
	csvwriter.writerow(['リスト名', 'カード名', '説明', '担当者', '更新日時'])
	for ticket in tickets:
		csvwriter.writerow(ticket)
```
ソースコードは[Github](https://github.com/KAZUKI1994/python_sandbox/blob/master/output_trello_cards_v2.py)にあげてます。

## 参考URL
- [Python公式リファレンス：14.1. csv — CSV ファイルの読み書き](https://docs.python.jp/3/library/csv.html)