見出し画像

【116日目】Django×Tweepy_取得したツイートデータをモデルに保存する

PythonでTwitterのデータを簡単に収集できるライブラリであるtweepyを使って色々と試しています。DjangoをベースにWebアプリ化していきたいと考えており、今回は取得したツイートデータをデータベースに保存する機能を作ってみます。

また、今回はデータベースはMySQLを採用しました。きちんとしたアプリになったら保存するデータ量も多くなるはずですし、sqlite以外も試してみたかったので。

DjangoとMySQLを接続する方法は以下の記事をご参照ください。


さて、データベースの準備ができたら、まずはmodels.pyでモデルを定義していきたいと思います。ちなみにDjangoで言うところのモデルとは、データベースでのテーブルと同義です。Excelで表現するとタブですかね。

工夫としては、ツイート一つ一つに固有の「tweet_id」はユニーク(重複無し)になるように設定しています。同じツイートをデータベースに登録しないようにするためです。

[models.py]
 
from django.db import models

class Tweets(models.Model):
    tweet_id = models.CharField(
        'ツイートID',
        max_length=255,
        blank=False,
        null=False,
        unique=True,)
    
    user_id = models.CharField(
        'ユーザーID',
        max_length=255,
        unique=False,)
    
    user_name = models.CharField(
        'ユーザー名',
        max_length=225,
        unique=False,)
    
    text = models.TextField(
        'ツイート内容',
        blank=True,
        null=True,)
    
    favorite = models.PositiveIntegerField(
        verbose_name='いいね数',)

    retweet = models.PositiveIntegerField(
        verbose_name='リツイート数',)


    created_at = models.DateTimeField(
        verbose_name='ツイート日時',)
    
    loaded_at = models.DateTimeField(
        verbose_name='データ取得日',
        auto_now_add=True)


続けてツイートデータを収集するための関数をtweepy.pyで定義します。こちらは昨日の記事で紹介したものとほぼ同じです。取得したデータをモデルと同じ順番に並び替えてリスト化しています。

1点だけ修正したのが、Cursorメソッドの引数にfromDateを渡しました。これは「いつまで遡るか」を指定していて、デフォルトだと過去30日間になっています。これを改めて設定した理由は最後に触れたいと思います。

[tweepy.py]
 
import tweepy


def get_tweets(search, num):
    api_key       = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    api_secret    = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    access_key    = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    access_secret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

    auth = tweepy.OAuth1UserHandler(api_key, api_secret)
    auth.set_access_token(access_key, access_secret)
    api = tweepy.API(auth)
    
    # API連携してツイート情報を収集
    tweets = tweepy.Cursor(api.search_30_day, label='test1', query=search, fromDate='202203040000').items(num)

    # 取得した情報から必要なものをリストに格納
    tweets = list(tweets)
    tweet_data = []
    for tweet in tweets:
        tweet_data.append([tweet.id, tweet.user.id, tweet.user.name, tweet.text, tweet.favorite_count, tweet.retweet_count, tweet.created_at])

    return tweet_data


最後にviews.pyです。ここでget_tweets()を呼び出して、データベースに保存するところまで定義しています。ただ、ユーザー名やツイート内容に絵文字を含んでいるとエラーになってしまい、DBに保存できませんでした。

今回は一旦コメントアウトして丸ごと除外していますが、追って絵文字を削除する対応をやってみたいと思います(全ての絵文字を削除することは難しそうなので、削除できるだけして、それでも残るものは除外する、という感じになりそうです)。

[views.py]
 

class TwitterAnalysis3(TemplateView):
    template_name = "tweepy_test/twitter_analysis.html"
    model = Tweets

    # 検索ワード
    searchkey = "めざまし"
    # 位置情報(指定なしにしている)
    location  = ""
    search ="{0} {1}".format(searchkey, location)
    item_num = 3
    
  # ツイートデータを取得
    tweet_data = tweepy.get_tweets(search, item_num)

    # 取得したデータをDBに保存(tweet_idが重複するとエラーになるので例外処理をしている)
    for i in range(len(tweet_data)):
        try:
            Tweets.objects.create(
                tweet_id   =str(tweet_data[i][0]),
                user_id    =str(tweet_data[i][1]),
                # user_name  =str(tweet_data[i][2]), # 絵文字があると上手くいかないため一時的にコメントアウトしている
                # text       =str(tweet_data[i][3]), # 絵文字があると上手くいかないため一時的にコメントアウトしている
                favorite   =int(tweet_data[i][4]),
                retweet    =int(tweet_data[i][5]),
                created_at =tweet_data[i][6],
                )
        except IntegrityError:
            pass

    def get_context_data(self):
        ctxt = super().get_context_data()
        # DBに保存したデータをとりあえず全て1つの変数に入れてテンプレートに渡す
        qs   = Tweets.objects.all()
        ctxt = {
            'tweet_set': qs
        }

        return ctxt


テンプレートはtweet_idをただ表示させただけです。

[twitter_analysis.html]
 
{% for tweet in tweet_set %}
<p>{{ tweet.tweet_id }}</p>
{% endfor %}


これでブラウザに以下のように表示されます。

tweet idを表示しているだけ



ただ、上記のコードには注意点があります。

  • 検索ワードにヒットする過去30日の全ツイートを取得したことになっている(fromDateを設定すれば取得するツイート数を抑えられる)

  • ビューが実行されるたびにtweepyのリクエストが送られている


何が問題なのかと言いますと、tweepyを使ったAPI連携には「取得できるツイート数」と「リクエストの回数」に制限があり、上記に気付かずに色々と試しているとあっという間に上限になってしまうことです。

僕は最初fromDateで制限をしていなかったですし、ちょこちょこ保存したり再起動したりしてビューが実行されていたので、すでに月間の容量をだいぶ消費してしまいました。。

Twitter Developer portal


views.pyで呼び出しているこいつ↓が犯人です。

tweet_data = tweepy.get_tweets(search, item_num)


このあたりを上手く制限する方法は今後考えてみたいと思います。


ここまでお読みいただきありがとうございました!


これまで修了したコース等

【YouTube_Django関係】
Pythonでウェブサービスを作ろう! 1
テンプレートをマスターしよう! 2
静的ファイルを配信しよう !3
本番公開しよう! 4
データベースと接続しよう! 5
ブログを作って学ぶモデル入門! 6
これが汎用ビューの力! 7
Djangoフォームを自由自在に操ろう! 8
djagoを最大限使って効率よくログインを作ろう! 9
ログイン完成!サインアップ & メール認証 10
データベースマイグレーション前編 15
データベースマイグレーション後編 16

【YouTube_Pandas関係】
3時間でマスター Pandas入門コース
Pandas20本ノック

【Paiza】
Aランクレベルアップメニュー 24/49問
データセット選択メニュー   12/17問
配列メニュー         64/64問
ループメニュー1      20/20問
ループメニュー2      12/20問
条件分岐メニュー       25/25問
二重ループメニュー      19/19問
配列活用メニュー       26/26問
文字列処理メニュー      30/30問
Bランクレベルアップメニュー 62/62問
Cランクレベルアップメニュー 30/30問
ランクB合格
ランクC合格
JavaScript体験篇       15/15講座
辞書(ディクショナリ)の基礎 8/8講座

【書籍/ブログ】
Django入門 | 初心者でも1時間でWebアプリ(Todoアプリ)を作成するコース
基礎からのMySQL
Web技術の基本
京大のPython教科書
Pythonデータベースプログラミング
Pythonエンジニアファーストブック

【Progate】
Python Ⅰ~Ⅴ
Python アプリ版 コースⅠ~Ⅴ
SQL Ⅰ~ Ⅳ
SQL アプリ版 コースⅢ
HTML&CSS 初級編

【環境構築】
Python, VSCode, MySQL(MAMP), Git / GitHub, HEROKU, anaconda, jupyter lab

この記事が気に入ったらサポートをしてみませんか?