PythonとTwitter APIを利用したツイート収集方法

2020-05-09
2020-05-09

Python と Twitter API を使って Twitter の分析を行いたいと思ったので、Twitter API について色々調べて試してみました。

Twitter API とは、公式の言葉を引用すると以下のようなものです。

Twitter にある情報をできるだけ広く共有するために、API (アプリケーション・プログラミング・インタフェイス)を通して Twitter データにプログラムレベルでアクセスし、企業、開発者、利用者に提供します。 引用:Twitter の API について

今回はこの Twitter API の概要と Python を利用した Search Tweets API の使い方についてまとめました。

Twitter API でできること

Twitter API では Twitter でできることはほぼ全てできます。 詳細はこちらのドキュメントに記載されています。

API を使うことで、Twitter でできることをある程度自動化できることがアプリと比較したメリットです。

例えば、Twitter のサードパティーサービスのようにツイートの予約・自動投稿が可能になります。まぁ、だいたいやりたいと思ったことはコードと API を組み合わせれば実現できそうです。

ただし、開発者が守るべき自動化ルールがあるので、自動化のプログラムを使用する前に確認しておきましょう。

今回使用するのは、ツイートの収集なのでSearch Tweets APIを利用します。

Twitter API の始め方

Twitter API を使用するには、Twitter のアカウントの他に Twitter API の登録申請が必要です。

詳しいやり方はこちらの記事が大変参考になります。

ポイントは申請内容はすべて英語で書く必要があることです。

とはいえ、私たちには Google 翻訳があるのでそこまで苦労することはないです。日本語で内容を書いて、Google 翻訳の結果をコピペすれば大丈夫です。

書く内容については、正直に書けば問題ないと思います。

私の場合は以下のような内容で申請しました。

私が twitter データを利用する理由は以下の2つです。

  • 1つ目は自分のブログに関連するトピックの分析です。twitter の情報を分析し、ユーザーに需要のある記事を書きたいと思ってます。
  • 2つ目は機械学習のためのデータ収集です。私は、機械学習を勉強中で生データを使った分析を試してみたいと思ってます。

申請結果は申請してすぐにきました。他の記事では1日やそこら待つとありましたが、私の場合は出してすぐにメールがきました。普通に書いて出せば、その日のうちに利用を開始できると思います。

利用できるようになったら必ず開発者契約およびポリシーは確認しましょう。

Search tweets API の制限

API が使えるようになったら早速試したいところですが、API にはいろいろ条件があるのでまずはそれらを確認します。

Seatch Tweets API にはStandardPremiumEnterpriseの3タイプがあります。3 タイプの比較についてはこちらの記事が参考になります。

今回利用する Standard Search API には以下のような制限があります。

  • 15 分間に 180 リクエストまで
  • 1度に取得できるツイート件数は 100 件
  • 遡れる期間は7日前まで

他の制限や Search API のパラメータなどについてはこちら(公式)に記載されてます。

コードを書くまえにcurlを利用した example があるので、そちらを試すとイメージが掴めます。

Python でツイートを取得する方法

いよいよ API を利用してツイートを取得していきます。

今回は Python を使って API を叩きます。Python には tweepy という Twitter API 用のライブラリがあるのでそちらを利用します。

ちなみに今回の検証環境は以下になります。

  • MacOS Mojave バージョン 10.14.6
  • Python 3.7.4

コードは以下のようにしました。あまり綺麗な書き方じゃないかもしれません。。

必要ないかもしれませんが、リクエスト前に sleep を適当に設定しました。

import tweepy
import pandas as pd
import datetime
from time import sleep
import argparse
parser = argparse.ArgumentParser(description='Twitter APIでツイート取得')
parser.add_argument('-q', help='検索クエリ')
parser.add_argument('--cnt',default=100, help='取得件数。デフォルト100件')
args = parser.parse_args()
# API認証情報
CONSUMER_API_KEY = ""
CONSUMER_API_SECRET_KEY = ""
ACCESS_TOKEN = ""
ACCESS_TOKEN_SECRET = ""
# tweepyでTwitter APIラッパーオブジェクト取得
def getAPI():
    auth = tweepy.OAuthHandler(CONSUMER_API_KEY, CONSUMER_API_SECRET_KEY)
    auth.set_access_token(ACCESS_TOKEN, ACCESS_TOKEN_SECRET)
    api = tweepy.API(auth)
    return api
# ツイートを取得
def getTweetData(api):
    tweet_data = []
    try:
        response = api.search(q=args.q, count=1, result_type="result_type", lang='ja',tweet_mode='extended')
    except tweepy.error.TweepError as tweepy_error:
        print(tweepy_error)
    next_max_id = response[-1].id
    i=0
    sleep(1)
    while True:
        print('検索ページ:' + str(i))
        try:
            response = api.search(q=args.q, count=100, max_id=next_max_id-1, lang='ja',tweet_mode='extended')
            if len(response) > 0:
                next_max_id = response[-1].id
            else:
                print("これ以上取得できません。検索ツイートが7日以上前か、検索ボリュームが少なすぎます。")
                break
            for tweet in response:
                user_mentions = []
                if tweet.entities["user_mentions"]:
                    for name in tweet.entities["user_mentions"]:
                        user_mentions.append(name["screen_name"])
                mention_names = ','.join(user_mentions)
                tweet_data.append([tweet.created_at.strftime('%Y/%m/%d'), tweet.id, tweet.user.name, tweet.user.screen_name, tweet.full_text.replace('\n',''), tweet.favorite_count,tweet.retweet_count,tweet.user.followers_count,tweet.user.friends_count,mention_names])
        except tweepy.error.TweepError as tweepy_error:
            print(tweepy_error)
            break
        except tweepy.error.RateLimitError as limit_error:
            print("検索上限に達しました")
            break
        i+=1
        if(i == 180):
            print("検索上限に達しました。上限は15分後にリセットされます")
            break
        sleep(2)
    print("Finish search!")
    return tweet_data
def makeFile(data):
    now = datetime.datetime.now()
    q = args.q.replace(' ', '_')
    # 結果保存パス、ファイル名
    file_name = 'path/{0}_{1}.csv'.format("query", now.strftime('%Y-%m-%d_%H-%M'))
    columns = ["投稿日", "ID", "User_name", "Screen_name", "text", "favorite", "retweet_count", "followers", "follows", "user_mentions"]
    df = pd.DataFrame(data) # 行の名前を設定
    df.columns = columns
    df.to_csv(file_name)
if __name__ == "__main__":
    api = getAPI()
    search_data = getTweetData(api)
    makeFile(search_data)

認証情報は API 利用申請を行い、API を使うアプリケーションの登録を行うと取得できます。

tweepy を使えば上記のように API のラッパーを簡単に扱えます。

検索クエリはコマンドラインから引数として渡します。検索結果は pandas を利用して csv にまとめます。今回は取得した情報全てではなく、いいね回数やフォロワー数などなんとなく役に立ちそうなものを抜粋しました。

このコードのポイントは以下の通りです。

  • tweet_mode='extended'を指定
  • ツイートの id を保持し、2回目の以降の検索はその id 以降からツイートを取得
  • ツイートに含まれるメンションを保存

1つ目のtweet_mode='extended'は指定しないと、文字数が多いツイートの文章が省略されてしまいます。指定することでツイート全文を得られます。 気をつけないといけないのは、tweet_mode='extended'を指定しない場合では、ツイート文の取得キーがtweet.full_textではなくtweet.textになります。

2つ目のidは、2度目に API を叩く時に1度目に取得したツイート以降の結果を取得するために利用します。Search Tweets API は1度に 100 件までなので、重複せずに結果を取得するために必要になります。

3つ目は、取得したツイート文に含まれるメンションを後で抜くために使います。正規表現で抜いてもいいのですが、API の結果を利用した方が確実なのでこちらを利用します。

実行するときは以下のようにターミナルに入力します。

python <ファイル>.py -q "<検索文>"

エラーなく終了すると、makeFile関数で指定したパスに結果が CSV で保存されます。

検索クエリのオプション

Search Tweets API では Twitter アプリの高度な検索と同じように検索に条件を設定できます。この設定を行うと、後でツイート文を分析するときにコード上で行う処理が減るので便利です。

公式ではStandard search operatorsと呼ばれています。

よく使うのをいくつ紹介します。先頭にハイフンがついてるオプションは否定を意味します。

  • lang:ja日本語のみ取得
  • -filter:linksURL を含むツイートを除外
  • -filter:retweetsアカウント名のツイートを除外
  • hoge -hugahoge を含むが huga は含まないツイート

これらのオプションをコード実行時の検索クエリに含めると指定した条件に合致したツイートのみが取得できます。

まとめ

今回は Twitter API の Search Tweets API について紹介しました。

ツイートはデータ分析をする上で非常に役立ちます。とくに自然言語処理を勉強する上で、大量の生データを扱えるのはありがたいです。

ツイートは本当にいろいろなパターンがあるので、自然言語処理の前処理の勉強にはもってこいです。

次回は今回のコードを利用したツイート収集自動化について書こうと思います。

参考書籍

API については以下の書籍が参考になりました。

Python を使った API 操作は以下の書籍を参考にしました。スクレイピングや機械学習についても書かれており重宝してます。私が持っているものの増補改訂版が出てたのでそちらを紹介します。