Twitter Streaming APIで取得した内容をJSON形式で書き出す

Streamingでツイート取得して、JSONファイルの書き出しまでやってみたのでメモ。
調べるとtweepyを使ったツイート取得が多かったので、もしかしたらそっちが主流なのか？
だからあえて使わないぜ！みたいな姿勢ではなく、REST APIで作ったものそのまま流用できないかってことでtweepyは使わず。
ちなみにpython3.5

このあたりを参考
https://dev.twitter.com/streaming/reference/post/statuses/filter
http://qiita.com/kenmatsu4/items/23768cbe32fe381d54a2
http://qiita.com/yubais/items/dd143fe608ccad8e9f85
http://qiita.com/Gen6/items/ce83a77217a86a26d907


## ソース
```
# -*- coding:utf-8 -*-

from requests_oauthlib import OAuth1Session
import json, datetime, time, sys

KEYS = { # 自分のアカウントで入手したキーを下記に記載
    'consumer_key':'*******',
    'consumer_secret':'*******',
    'access_token':'*******',
    'access_secret':'*******'
   }

# Twitter APIへの接続
twitter = OAuth1Session(KEYS['consumer_key'],KEYS['consumer_secret'],
                        KEYS['access_token'],KEYS['access_secret'])

nRstTm = 15 # Rate Limited待機時間
stKeyWrd = 'twitter' # 検索ワード

url = 'https://stream.twitter.com/1.1/statuses/filter.json'

# ツイートのdatetimeを日本標準時間に変換
def str_to_datetime_jp(datetimes):
    dts = datetime.datetime.strptime(datetimes,'%a %b %d %H:%M:%S +0000 %Y')
    return(dts+ datetime.timedelta(hours=9)).strftime("%Y-%m-%d %H:%M:%S")

f = open("teststream.json", "w",encoding='utf-8')
while(True): 
    try:
        req = twitter.post(url,
                    data= {"track":stKeyWrd},
                    stream = True)

        if req.status_code == 200: 
            for line in req.iter_lines():
                work = json.loads(line.decode('utf-8'))
                workuser = work['user']
                tweet_json = {"tweetId":workuser["id"],
                              "name":workuser["name"],
                              "screen_name":workuser["screen_name"],
                              "text":work["text"],
                              "created_at":str_to_datetime_jp(work["created_at"])
                              } 
                print('write')
                json.dump(tweet_json, f, ensure_ascii=False, indent=2,sort_keys=True)

        # 短時間でアクセスしすぎたら420エラーになるので待機
        elif req.status_code == 420:
            print('Rate Limited：',nRstTm,'分待機')
            time.sleep(nRstTm)
        else:
            # とりあえず処理抜けとく
            print('req.status_code',req.status_code)
            break

    # streamで取得できない場合、以下例外になるので再度取得しなおし
    except json.JSONDecodeError as e:
        print('再取得')
        pass
    except KeyboardInterrupt:
        print('処理終了')
        f.close()
        break
    except:
        print('except', sys.exc_info())
        pass
```

## 処理で詰まったところ

ここでstreaming開始して、statusが200ならループしてJSONを書き込むというシンプルな作り。
俺のレベルが低すぎてこれが正直精いっぱいなだけ。

詰まったのがreq.iter_lines()で1件ずつ処理しますよってところ。

```
            for line in req.iter_lines():
                work = json.loads(line.decode('utf-8'))
```

ここのデータの渡し方で、変数lineがbytes型なので、単純にjson.loadsするとstr型にしろって怒られちゃう。
decode('utf-8')で変換してあげないとダメってことを知らず。

あと全然ツイートされていないものでstreamingするとjson.loadsしたくても変数lineにないで！ってなるので以下でcatchしてあげた。

```
    except json.JSONDecodeError as e:
        print('再取得')
        pass
```

## 分からないところ

実装していて分からないところが２つあって上手くカバーできてない。
1. キーワード検索で助詞を含むワードが取れない
2. 420エラーがでまくる

### キーワード検索で助詞を含むワードが取れない
どうやらキーワード検索したワードの前後に何かしらの言葉がくっついていると取得できないみたい。
https://github.com/tsupo/Twitter-API-Specification--written-in-Japanese-/blob/master/twitterAPI.txt

例えば「アイカツ！」をキーワード検索して、「#アイカツ！」みたいにハッシュタグ（ワード間に半角スペース）であればいいんだけど、「アイカツ！で一番かわいいのは霧矢あおいちゃん」みたいに助詞が入ると途端にとってこない。

アイカツスターズ！のtwitterの実況取りにくいから正直すげー困る。

なんかこれ回避方法とかあるのか。自信ﾆｷご教授ｵﾅｼｬｽ!

### 420エラーがでまくる
短期間で何度も接続・再接続しようとするとお前つなぎ過ぎじゃって言われて420エラーになってしまう。
https://dev.twitter.com/overview/api/response-codes
https://dev.twitter.com/rest/public/rate-limiting

420エラーで再接続待ちするのはいいけど、実際何分待てばいいのかさっぱりわからん。RESTだときっちり決まってるのに、なぜstreamingは明言されてないんだよ。

正直このエラーになって再接続待ちしている間にツイート流れるので、このエラーが出力しないように回避したいんだけど、やり方不明。そもそもできんの？

実装が悪さしている可能性が結構高い気はしてる。RESTと同じように何度もアタックしちゃうのは悪手な気がするし。