Python:webAPIからJSONデータの読み込み

## まず、JSONってなんだ？
人間にもコンピュータにもわかりやすいデータ構造らしいです(ざっくり)
[JSONとは - Qiita](http://qiita.com/SotaSuzuki/items/c3b46c4e24c1ca9b4d37#%E6%96%87%E5%AD%97%E5%88%97%E3%81%AE%E8%A1%A8%E7%8F%BE)
* * *
jsonデータをpythonで読み込むにはjsonライブラリをimportすればできるようになるらしい。

読み込んだらdictionary型と同じ扱い方ができるらしい。(dictinary型についてよくわからないのでここでお勉強します。)

## dictionary型について
- dictionary型はkey(キー)とvalue(値)のセット(要素)になっている
- javaでいうhashMapみたいなもの？(hashMapうる覚えです)
- 要素の順序はないため、要素を取り出すためにはキーを指定して取り出すことになる

### keyを指定して値を取り出す
```test01.py
# -*- coding: utf-8 -*-

dict = {"name": "tamago", "color": "yellow"}

# keyを指定してvalueを取り出す
print dict["name"]
print dict["color"]
```

```test01.pyの出力結果
tamago
yellow
```

もし、存在しないkeyを指定して取り出そうとすると、Errorになってしまう。


### keyとvalueのリストを取得
- keyのリストを取得
- valueのリストを取得
- keyとvalueのリストを取得

```test02.py
# -*- coding: utf-8 -*-

dict = {"name": "tamago", "color", "yellow"}

# keyのリストを取得
keyList = dict.keys()
print keyList

# valueのリストの取得
vakList = dict.values()
print valList

# keyとvalueのリストの取得
list = dict.items()
print list
```

```test02.pyの出力結果
['color', 'name']
['yellow', 'tamago']
[('color', 'yellow'), ('name', 'tamago')]
```

dictionary型には要素の順番はないのでどのように取得できるかはわからない

ざっとdictionaryについては理解できました！！

## WebAPIからJSONデータを取得

今回、使用するwebAPIはツイキャスのコメント取得API（[コメント取得API - ツイキャス](http://twitcasting.tv/indexapicommentlist.php)）です

WebAPIからJSONデータを取得するときには`urllib`をインポートし、メソッドを使い、取得します
取得したデータをpythonで扱えるようにするには`json`をインポートし、メソッドを使います

```test02.py
# -*- coding: utf-8 -*-

import urllib
import json
import sys
import codecs

# これで、cp932に変換できない文字はなくすことができる
sys.stdout = codecs.getwriter(sys.stdout.encoding)(sys.stdout, errors='ignore')

# webAPIからJSONの形式の文字列の結果をもらう
def dataGet():

    # URIスキーム
    url = 'http://api.twitcasting.tv/api/commentlist?'

    # URIパラメータのデータ 
    param = {
        'user': 'tamago324_pad',    # 取得したい人のID
        'type': 'json'             # 取得するデータの指定
    }

    # URIパラメータの文字列の作成
    paramStr = urllib.urlencode(param)  # type=json&user=tamago324_pad と整形される

    # 読み込むオブジェクトの作成
    readObj = urllib.urlopen(url + paramStr)

    # webAPIからのJSONを取得
    response = readObj.read()

    # print type(response)  # >> <type 'str'>

    return response

# webAPIから取得したデータをJSONに変換する
def jsonConversion(jsonStr):

    # webAPIから取得したJSONデータをpythonで使える形に変換する
    data = json.loads(jsonStr)
    return data

    # 日本語が u'\u767d' のようになってしまうため、Unicodeに変換する
    # return json.dumps(data[0], ensure_ascii=False)

# コメントの投稿時間をh:mm:ssに変換する
def getElapsedTime(duration):

    secStr = ""
    minStr = ""

    hourInt = duration / 3600
    minInt = (duration -3600 * hourInt) / 60
    secInt = duration % 60

    if minInt <= 9:
        minStr = "0" + str(minInt)
    else:
        minStr = str(minInt)

    if secInt <= 9:
        secStr = "0" + str(secInt)
    else:
        secStr = str(secInt)

    if hourInt >= 1:
        return str(hourInt) + ":" + minStr + ":" + secStr
    else:
        return minStr + ":" + secStr

if __name__ == '__main__':

    resStr = dataGet()
    res = jsonConversion(resStr)

    # 取得したデータを表示する
    for item in res:
        print getElapsedTime(item['duration']) + " " + item['userstatus']['name'] + " " + item['message']

```

```実行結果
10:14 たまたまご テスト
09:49 たまたまご コメント
```

### WebAPIからJSONデータの取得
`def jsonGet():` では<strong>webAPIからJSONデータを取得しています</strong>
`urllib.urlencode()`でdictionaryからURIパラメータの文字列を作成しています。このメソッドで返される文字列はkey=valueの形で複数ある場合には&で結合されていきます(例： `key1=value1&key2=value2` )
dictionaryには順序はないので結合される順番は指定できません

`urllib.urlopen()` でJSONデータを読み込むためのオブジェクト（object）を作成している

作成したオブジェクトのメソッド(`object.read()`)でwebAPIからJSONデータを取得している
戻り値は`str`型で返ってくるらしい

### 取得したデータをPythonで扱えるJSONへ変換
`json.loads()`で取得したJSONをpythonで扱えるように変換する。しかし、unicodeで返してくるため日本語が`\u3063`のようになってしまう`json.dumps(data, ensure_ascii=False)`でしっかりと日本語が表示できた！と思ったら文字列になっていた...`data`は`list`だったのに...
これは一つ一つunicodeからstrに変換していくしかないのか...

どうしようか悩んでいたけど、ひとつだけコメントを取得してみようとおもい、`prinnt data[0]['message']`で表示してみると、しっかりと日本語で表示されたんです！！！が、コメントに`꒳`が含まれていて、表示しようとしたら`UnicodeEncodeError: 'cp932' codec can't encode character u'\ua4b3' in position 0: illegal multibyte sequence`というエラーがでてきた

> <b>UnicodeEncodeError でコンソールに文字を表示できないときの対処</b>
[cp932で表現できない文字がたまに混ざるユニコード文字列をWindowsのコンソールにprintしたい場合 - 西尾泰和のはてなダイアリー](http://d.hatena.ne.jp/nishiohirokazu/20120112/1326355987)
`sys.stdout = codecs.getwriter(sys.stdout.encoding)(sys.stdout, errors='ignore')`とかくことでcp932で表現できない文字は表示しないようにできる（仕組みはわかっていないです...こんど解明しようと思っております）

今はコンソールでやっていますが、windowsアプリなどで表示できれば見た目ももっとよくできるかと思います


[辞書(ディクショナリ) - Python入門](http://www.pythonweb.jp/tutorial/dictionary/)
[ライブラリ：json - Life with Python](http://www.lifewithpython.com/2013/06/json.html)
[20.5. urllib — URL による任意のリソースへのアクセス — Python 2.7.x ドキュメント](http://docs.python.jp/2/library/urllib.html#urllib.urlencode)
[PythonでYahoo APIを使ってみる – BTY備忘録](http://bty.sakura.ne.jp/wp/archives/787)
[Pythonでのget,post通信メモ - Qiita](http://qiita.com/Thiru0000/items/9259c3940ed91285c066)
[日本語を含むUnicodeのJSON文字列を得る. - Qiita](http://qiita.com/yamaneko1212/items/83d42ab1bdf369fd494a)
[18.2. json — JSON エンコーダおよびデコーダ — Python 2.7.x ドキュメント](http://docs.python.jp/2/library/json.html)