ツイートを長期間収集する実験(集計＆中身確認編)

# 前回まで。

 - [x] プログラム準備完了。
 - [x] ライブラリの不具合修正実施
 - [x] 実行開始！
	- [x] 一応最初のピークは問題なかった？
 - [ ] とりあえず集計してみよう
 - [ ] 外から覗いてみよう

# 時間ごとの集計をしてみる
　ひとまず１週間ほど経過しました。とりあえず今のところ無事に動いているようです。
　となると、次にほしいのは現状の入力数とか、時間ごとの集計になるわけですが。

```
>>> db.xxx.count()
```

　とやれば、カウント自体は上がっているのがわかるのですが、いくらなんでも正確とは言い難い……どうにかして、時間単位のツイート数集計に持ち込む必要があります。

## MapReduceで集計
　MongoDBでの集計手段は何やら複数あるようですが、とりあえず「薄い本」をもとにMapReduceでもってして集計してみることにします。
　……JavaScriptも触るの初めてなんだけどなぁ、とか思いつつ、ググりまくって

```JavaScript:check.js
db.xxxxx.mapReduce(
    // map
    function() {
    	
    	d = new Date(Date.parse(this.created_at) + 32400000);
    	p = d.getFullYear() + "/" + ("0" + (d.getMonth() + 1)).slice(-2) + "/" + ("0" + d.getDate()).slice(-2) + " " + ("0" + d.getHours()).slice(-2) + ":00:00"
        emit(
            p,
            1
        );
    },

    // reduce
    function(key, values) {
        return Array.sum(values)
    },

    {
        query: {},
        out: "TweetsCount"
    }
)
```

　こんな感じに。
　(JavaScriptの日時formatって、こんなめんどい手段しかないんですっけ？)

```
# mongo localhost/TwitterDB check.js
```

　こんな感じで実行すると、別のCollection「TweetsCount」に結果が格納されます。

```
(ピーク発生個所だけ抜粋)
{ "_id" : "2016/10/28 13:00:00", "value" : 67 }
{ "_id" : "2016/10/28 14:00:00", "value" : 47 }
{ "_id" : "2016/10/28 15:00:00", "value" : 102 }
{ "_id" : "2016/10/28 16:00:00", "value" : 103 }
{ "_id" : "2016/10/28 17:00:00", "value" : 2850 }
{ "_id" : "2016/10/28 18:00:00", "value" : 5317 }
{ "_id" : "2016/10/28 19:00:00", "value" : 4324 }
```

　とりあえず取れてるようです。なーんか全体的に少ないかな？という気もするのですが<sub>(ピーク1ケタ足らん気がする……たぶん検索キーの都合)</sub>。
　この程度の実行なら、さほどの負荷にはならないようです。100日分とかまとまったらまた変わってくるのかもしれませんが……。

# DBの中身をチェックしよう
　現在動かしている取得プログラムは、画面上の標準出力に何も出ないので、何が格納されたのか確認できません。
　MongoDB直接覗けば見れますが、リアルタイムの取得状況までは分からないですし、見るだけなら不要な項目がJSON上にたくさん入っており、率直に言って見づらいです。

　この辺どうにかして、リアルタイムで(またはある程度の追従で)ツイート内容がチェックできるスクリプト、がほしいよなぁ、という話になります。

　なんかいろいろ手段もありそうなのですが、手っ取り早くて大げさにならなくて、見たいものだけ見るような感じにがりごりやったらこんな感じ(実装2hくらい)。

```Python:InsertChecker.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-

from pymongo import MongoClient
import json

import time

# MongoDB 接続関係の変数
HOST = 'mongo'      # ホスト
PORT = 27017            # ポート(デフォルト:27017)
DB_NAME = 'TwitterDB'   # DB名
COL_NAME= 'xxxxxx'    # コレクション名


# ------ ここからメイン処理 ------

try:
    Client = MongoClient(HOST, PORT)
    db = Client[DB_NAME]
    Collection = db[COL_NAME]
    print('DB準備完了')
    
    twCnt = Collection.count()  # 一番最初のカウント取得
    
except pymongo.errors.PyMongoError as exc:
    # 接続エラー
    print('DB接続エラー')


while(True):        # 無限ループ
    try:
        
        if(Collection.count() > twCnt):
            for doc in Collection.find(skip=twCnt):
                
                if("retweeted_status" in doc):
                    if("extended_tweet" in doc["retweeted_status"]):
                        # RTの長文
                        print("RT @" + doc["retweeted_status"]["user"]["screen_name"] + ": " +doc["retweeted_status"]["extended_tweet"]["full_text"])
                    else:
                        # RTの短文
                        print("RT @" + doc["retweeted_status"]["user"]["screen_name"] + ": " +doc["retweeted_status"]["text"])
                else:
                    if("extended_tweet" in doc):
                        # 長文
                        print(doc["extended_tweet"]["full_text"])
                    else:
                        # 短文
                        print(doc["text"])
                
                print(u"{name}({screen}) {created} via {src}".format(name=doc["user"]["name"], screen=doc["user"]["screen_name"],
                    created=doc["created_at"], src=doc["source"]))
                print(u"--------------------------------------------------")
        
        twCnt = Collection.count()
        
        # チェック間隔は３秒ごとくらいで(流速次第で10秒でもよいか？)
        time.sleep(3)
        
    except KeyboardInterrupt:
        # CTRL+C
        print('CTRL + C で終了。')
        ExitCode = 0
        break
```

　(途中のprint()文の記法が変わっているのは、参考資料からのコピペが混じるためです)
　やってることは簡単で、定期的にコレクションの数をチェックして、多くなっていれば増えた分を整形して出力する、というものです。

　なにやら<a href="https://dev.twitter.com/overview/api/upcoming-changes-to-tweets">ツイート文言の拡張</a>なる仕様変更があった結果、中盤のifで以下の４パターンに分岐させることに。
・RTのツイートで、かつ拡張仕様(長文)のツイートのパターン
・RTのツイートで、かつ標準仕様(短文)のツイートのパターン
・通常のツイートで、かつ拡張仕様(長文)のツイートのパターン
・通常のツイートで、かつ標準仕様(短文)のツイートのパターン

　あとは時間表示してユーザ名表示しておっけー。こんなにウルトラ適当でも、"tail -f"っぽく表示される！ステキ！

## 小改造
　これでもだいたいやりたいことを満たしているのですが、便利を追求したくなるのが人情。
### Fav数、RT数を表示
　RTされまくってるツイートが、実際どれだけRTされてるの？ くらいはほしいよねーとか思うわけで。

```
print("\n<RT: " + str(doc["retweeted_status"]["retweet_count"]) + " cnt, Fav: " + str(doc["retweeted_status"]["favorite_count"]) + "cnt >")

```

　こんな感じのをRTの際に表示を行う分岐の中に挿入(インデントは揃えること)。RTされるたびにカウントアップしてるのがわかります。

### 時刻表示を読みやすいように
　Twitterから送られるJSON内の時刻表示は、日本人的には読みづらいのでこれを改変。

```
d = datetime.strptime(doc["created_at"],'%a %b %d %H:%M:%S +0000 %Y') + timedelta(hours=9)
```

　とやってdatetime形式に変換ののち時刻格納個所を

```
created=d.strftime("%Y/%m/%d %H:%M:%S")
```

　こんなに置き換えれば完成。「from datetime import datetime, timedelta」も忘れずに。

### クライアント名表示からHTMLタグを抜く
　ツイートがどんなクライアントから送信されたかが表示できるのですが、この項目、HTMLタグが入れられるためか、実際タグが入ってて見づらいことこの上ありません。
　「import re」として正規表現を有効にして、doc["source"]を指定している箇所でこんな感じにすればあら不思議、タグがきれいになくなります。

```
src=re.sub("<.+?>", "", doc["source"])
```

(タグ以外がなくなる可能性もないわけではないが、今のところうまくいってる。)


# つぎになにやるか(ノープラン)
　とりあえずこれで、
・ 時間単位でのツイート数
・ リアルタイムで取得しているツイートの表示

　ができるようになりました。やはりちゃんとツイートが流れているのを見ると精神的に安心しますね。

　次の目標は
・現在一番RTされてるツイートの抽出
・Twitterクライアントの利用統計
・ツイートから店舗<sub>(換言)</sub>名を抽出して、言及回数を測る
　あたりでしょうか。ちまちま作ってみようと思います。

(しつこく続く。)