(2018/07/22)きょうは Shonan.py のもくもく会に来ています

どうも、初心者ではなくなった40代のおっさんです(Shonan.py もくもく会公認)
前回参加時に考えていたTwitterAPIで取得したツイートデータをSqliteのDBに突っ込むアイディアですが、JSONの抱える属性の数は一定していないので、id だけを Key として抱えて、生のママ保存しようかとアイディアを修正して、それを実現しようかと思います。

ここ最近は溜まったヨドバシのポイントでを[これ](http://www.jp.square-enix.com/octopathtraveler/)や[これ](https://www.amazon.co.jp/dp/4040728343/)購入したりしたので、Pythonに余り触れて居なかったのが痛い。

## 14:12更新 ひとまず、JSONの中身をザックリsqliteにたたき込む
と言う方針でチマチマ書いてます。JSON の中身を丸ごと TEXT 形の列にたたき込み、それを Twert の IDをキーにして保存する考え。
もしかしたら、メインのメッセージ文字列くらいは更に保存しても良いのかも知れない、検索処理のために。

## 14:43 更新 sqlite3のエスケープ処理に悩む

```エスケープシーケンスが必要な処理.py
#挿入用クエリ文字列を取得する
def GetInsertQuery(org_val):
    # org_val には一ツイート分のデータが dictionaly 形式で格納されている
    # 直接インサートしない列名をタプルに用意する
    column_name = 'id,tweet_text,JSON_DATA'
    value_text = ''

    #id を取得
    id_val = org_val['id']
    text_val = org_val['text']
    # ここに text_val,org_val のエスケープシーケンス処理を挟まないとDBへの挿入は険しそう。
    # 何が入ってるかわからないモノを突っ込むわけで。
    value_text = '{0},''{1}'',''{2}'' '.format(id_val,text_val,org_val)
    ret_query = 'INSERT INTO TBL_TWEET ({0}) VALUES ({1})'.format(column_name,value_text)
    return ret_query
```

色々書いてみてるんだが、シングルquartでいっぱいの文字列を生のママたたき込まなきゃいけないから、あとテキストにダブルクォートとか当然に含まれる可能性があるもんだから、エスケープシーケンスのことを意識してやんないと行けない。
正規表現で一括置換するべきだろうか。ちょっと思案しなきゃいけない。

## 14:52 正規表現の置換とかするよりも
https://docs.python.org/3.6/library/sqlite3.html
上記を参考に、DBAPI 側に任せてしまうのがクレバーなやり方、と教わったのでやってみることとする。
ひとまず、TEXT型の長さの制限は考えなくても良い、と言う思い込みで進める。


## 15:57 テーブルへのインサートがなかなか上手く行ってくれてない
いろいろやっているのだけども、どうにもテーブルへのインサートが上手く行かない。
sqlite の journal ファイルは作られてるので、アクセスしてインサートを試みるとこまで入っていると思うのだが、commit してもその内容が反映されてくれない。

```実装しているとこ.py
import sqlite3  #sqlite3を使用する
folder = os.path.dirname(os.path.abspath(__file__))
DATABASE = folder + '/samplex.db' #データベース名
conn = sqlite3.connect(DATABASE) #データベースへのコネクション

def GetTwitterLogInfo():
    # 取得したTwitterのログを生のママ保存する。
    # 保存する際、TweetのIDはキーの情報として別の列に保存する。
    # また、IDが取得できなかったときのため、一応IDENTITY列を一つ用意する。
    CreateInfoTable() # テーブルを作成する
    tw_session = OAuth_ORG.get_twitter_api() # Twitter のセッションを取得する
    # 特定のアカウントの情報を取得する
    params = {
        'screen_name': 'anisama',  # 取得するのスクリーンネーム
        'count': 100
    }
    end_point = 'https://api.twitter.com/1.1/statuses/user_timeline.json' #データ取得用のエンドポイント
    req = tw_session.get(end_point, params=params)   #リクエストを投げる

    if req.status_code == 200:
       tweets = json.loads(req.text)
       InsertMainData(tweets)
    else:
        print("ERROR!: %d" % req.status_code)

def CreateInfoTable():
    # TWEET の値を格納するためのテーブル
    query1 = '''CREATE TABLE IF NOT EXISTS TBL_TWEET_INFO 
    ( 
    uniq INTEGER PRIMARY KEY, 
    id INTEGER, 
    tweet_text TEXT,
    JSON_DATA TEXT
    ) '''
    c = conn.cursor()   #カーソルを取得
    c.execute(query1)   # SQLの実行

#SQLite3で、データを格納するためのテーブルを構築・挿入する
def InsertMainData(v_json):
    #取得した JSON の値をハッシュテーブルに対して格納していく
    c = conn.cursor()   #カーソルを取得
    t_status = v_json
    
    for st in t_status: #一ツイート分のデータが st に入っている。これを解析してテーブルにたたき込んでいく
        #SQL をデータから取得し作成する
        #GetInsertQuery(c,st)   #一ツイート分のデータをINSERTするクエリを生成
        id_val = st['id']
        text_val = st['text']
        value_text = [(id_val,text_val,'')]

        try:
            c.executemany("INSERT INTO TBL_TWEET_INFO (id,tweet_text,JSON_DATA) VALUES (?,?,?)" ,value_text)
            conn.commit
        except Exception as inst:
            print("Unexpected error:", inst)
```

なにがあかんのやろ…例外は特に吐いてないので呼び出し方とかはおかしいとも思えないのだけど。
本来 value_text の3番目の値は、Tweet全体のデータである st の中身を文字列化したモノを格納する予定なのだけど、insert　が上手く行かないのでひとまず空を与えているのだけどもね…

##17:11 ダメだった理由がわかりました

``` ダメだったところ.py
#SQLite3で、データを格納するためのテーブルを構築・挿入する
def InsertMainData(v_json):
    #取得した JSON の値をハッシュテーブルに対して格納していく
    c = conn.cursor()   #カーソルを取得
    t_status = v_json
    
    for st in t_status: #一ツイート分のデータが st に入っている。これを解析してテーブルにたたき込んでいく
        #SQL をデータから取得し作成する
        #GetInsertQuery(c,st)   #一ツイート分のデータをINSERTするクエリを生成
        id_val = st['id']
        text_val = st['text']
        value_text = [(id_val,text_val,'')]

        try:
            c.executemany("INSERT INTO TBL_TWEET_INFO (id,tweet_text,JSON_DATA) VALUES (?,?,?)" ,value_text)
            # conn.commit # ← 誤ったところ
            conn.commit() # ← 正解
        except Exception as inst:
            print("Unexpected error:", inst)


```

**クラスのメソッドコールするときの、末尾の()が抜けてたという**初歩的ミスでした…お恥ずかしい。
これで1時間半悩んでたんだからなぁ… 
.NETだと末尾に()無くてもコールされてしまうので、その癖が抜けてなかったようです。

Python初心者脱出に失敗しました。ただいま。

##17:16 本日の学び
命名規則について、こういう言い回しがあるのを知る(こういう表現を使って仕事しない環境なのが丸わかりである)
https://www.indetail.co.jp/blog/7208/

スネークケースとキャメルケース。
Pythonでは、関数名や変数名は snake_case(スペースをアンダーバーで表現する)、クラス名やモジュール名はCamelCase(単語の頭文字を大文字にして連結する)のがよりお作法に則ってる、と言うこと。
ご指導ありがとうございます。

##17:47 できたぞー！！
というわけで、雑にTwitterログをDBにたたき込む所までは出来ました。
ここからもう少し拡げていきたい。