【Python×データ分析】TwitterデータをMongoDBに保存できるようにする

こんにちは。最近は、SNSデータをもっと自由に分析できるようになりたいなぁということで関連した記事をよく書いていますが、今回もそのシリーズになります!

前回書いたTwitterデータの分析記事でご紹介した方法の発展形として、今回は、TwitterAPIで取得したデータをデータベースに逐次保存していけるような仕組みを作ってみようと思います。

テキストデータの管理に相性が良いMongoDBをローカルに構築した状態でPythonコードを書いていきます。

Contents

前提となるステップ

まず、PythonでTwitterデータを取得できるようになっていること。

そして、ローカルにMongoDBがインストールされていること。

TweetデータをMongoDBに保存する方法

参考にした記事

今回、以下の記事を参考にさせていただきました。

スタバのTwitterデータをpythonで大量に取得し、データ分析を試みる その1

「停電」に関するツイートをpythonで収集して、WordCloudで可視化してみた

PythonからMongoDBにアクセスするためのドライバをインストール

はじめに、PythonからMongoDBを操作するためのドライバをインストールしておきます。

conda install -c anaconda pymongo

ツイートを取得してMongoDBに保存するコード

以下が、コードになります。

何度もコードを実行することを想定して、2回目以降同じコードを実行した場合には、MongoDBに入っているツイートデータの最大IDを取得してきて、それよりも最新のデータのみを取得して保存するようにしました。

import pymongo
from pymongo import MongoClient
from collections import defaultdict

connect = MongoClient('localhost', 27017)
db = connect.tweetDB #データベース名
tweetdata = db.MachineLearning #ツイートデータを格納するコレクション(テーブル)名

def getTwitterData_DB(key_word, repeat):
    url = "https://api.twitter.com/1.1/search/tweets.json"
    params ={'q': key_word, 'count':'100','lang':'ja', 'result_type':'recent'}
    tweets = []
    mid = -1
    break_flag = 0
    
    ## MongoDBに保存されている最新のIDを取得(差分のみを取得)
    if tweetdata.count() == 0:
        max_id = -1
        print("a")
    else:
        max_id = tweetdata.aggregate([{'$sort': {'id': -1 }}, {'$limit': 1}]).next()["id"]
        print(max_id)
        
    for i in range(repeat):
        params['max_id'] = mid
        params['since_id'] = max_id
        res = twitter.get(url, params = params)
        if res.status_code == 200:
            sub_tweets = json.loads(res.text)['statuses']
            limit = res.headers['x-rate-limit-remaining'] if 'x-rate-limit-remaining' in res.headers else 0
#            print("API残接続可能回数:%s" % len(limit))            
            tweet_ids = []
            for tweet in sub_tweets:
                tweet_ids.append(int(tweet['id']))
                tweets.append(tweet)
                
                ## Mongo DBに保存
                tweetdata.insert(tweet)
                
            if len(tweet_ids) > 0:
                min_tweet_id = min(tweet_ids)
                mid = min_tweet_id - 1
            else:
                break_flag = 1
                break;
                
            ## 終了判定
            if break_flag == 1:
                break;
                
        else:
            print("Failed: %d" % res.status_code)
            break_flag = 1
            
    ## MongoDBに登録したツイートデータの日付更新
    for d in tweetdata.find():
        tweetdata.update({'_id' : d['_id']}, {'$set' : {'created_at_localized' : str_to_date_jp(d['created_at'])}})
    
    print("ツイート取得数:%s" % len(tweets))
        
    return tweets

# 文字列を日本時間2タイムゾーンを合わせた日付型で返す
def str_to_date_jp(str_date):
    dts = datetime.datetime.strptime(str_date,'%a %b %d %H:%M:%S +0000 %Y').replace(tzinfo=datetime.timezone.utc)
    dts = dts.astimezone(pytz.timezone('Asia/Tokyo'))
    return str(dts)

直近のpymongoバージョンでは、上のpymongoのいくつかの構文が廃止されて使えなくなっているようです。(insert、update、countなど)

insert() はinsert_many([]) or insert_one()、count()はcount_documents({})、update()はupdate_many or update_oneに変わっているので適宜変更ください。

“機械学習”を含むツイートを最大18000件(一度に取得できるツイート数のAPI側の制限)取得しにいきます。

tweets = getTwitterData_DB("機械学習", 180)

MongoDBに登録されたデータの確認

上記のコードを実行することでMongoDBにツイートが登録されたはずです。MongoDB CompassからDBの状態を確認してみます。

Pythonコード上で事前に指定しておいたデータベース名とコレクション名でデータが登録されていることが確認できました!

Mongo DB Compass

MongoDBからデータを抽出する方法

MongoDBに継続的にデータを貯められるようになったところで、最後に保存したデータを抽出してデータ分析に使える形にしようと思います。

これは簡単で以下のコードでDataFrame化してやれば良いです。下記は全件抽出時のコードなので、条件指定があればfind()の中に条件文を記載します。

df_tweet = pd.DataFrame(tweetdata.find())

以上、今回はMongoDBを使う仕組みの構築を行いました。

この仕組みを使った実際のテーマを定めたデータ分析はまた別の記事でご紹介できればと思います。

本日も最後までご覧いただきありがとうございました。参考になった!という方は下のいいねボタンを押していただけると励みになります!

おしまい

この記事を気に入っていただけたらシェアをお願いします!

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

ABOUT US
Yuu113
初めまして。ゆうたろうと申します。 兵庫県出身、東京でシステムエンジニアをしております。現在は主にデータ分析、機械学習を活用してビジネスモデリングに取り組んでいます。 日々学んだことや経験したことを整理していきたいと思い、ブログを始めました。旅行、カメラ、IT技術、江戸文化が大好きですので、これらについても記事にしていきたいと思っています。