Twitter APIの申請からPythonでのTwitter API実行まで(2019.10某日の備忘メモ)

##Twitter APIの利用申請
　数年前のTwitter社のTwitterAPIの管理がそんなに厳しくなかった時代に、 TwitterAPIを当時勉強中だったRubyでスクリプト書いてちょこちょこ触っていたのですが、Twitter社のAPI管理が厳格化されて、API利用の申請などがめっちゃ煩雑になったということで、申請するのめんどくさいのでAPIを利用するのを数年間止めていたものの、仕事？ではないけれどTwitterで任意の文字列で検索したいケースが最近生じたため、今回TwitterAPIの利用申請をすることにした。

参考にした記事↓
https://qiita.com/kngsym2018/items/2524d21455aac111cdee

　TwitterAPIの申請等は、上記URLのqiita記事にある通りにやればすんなり申請通るかと思われ。自分も１日くらいで利用可能になりましたです。

　TwitterAPIの申請で一番の**難所**になるのは、「Twitter Developer」のページにアクセスして、<font color=red>200文字以上の英文で、自分がなぜTwitterAPIを利用するか？またどのようにTwitterAPIを利用するのか？</font>を所信表明的な文章を明記するところかと。英語が得意でない方もいるかもしれないが、今はGoogle翻訳が昔と比べて格段に性能が向上しているので、適当に日本語で文章を生成して、Englishに変換すればそれらしい英文が生成できるかと思う。(←注：かの80歳を超えたおばあちゃんが、iOSアプリをプログラミングしてApple社のアプリ申請をGoogle翻訳使って申請を通す時代ですからね。さもありなむ。)

　参考までに、以下は自分が申請時に入力した英文を以下に記して、こんなイメージの文章を申請時に登録したことをログとして残しておく。自分のつたない英語力では参考になるかは定かではないが、参考にされたし↓
######Q1)Twitterデータをどのように分析するのかを説明 (※200文字以上)
>例）Hi,team.
I work for a Japanese retail company.
For marketing research, I would like to collect and analyze tweets using the Twitter API, such as the sales situation of our products and responses to customer products. 
I can program in Python, so I'm going to write a script in Python to run the Twitter API.
(<font color=blue>私は日本の小売業界の会社で働いている者です。
マーケティング調査の一環で、自社製品の売上状況やお客さんの購入後の反応を知るためにTwitter APIを使ってTwitterのツイートを収集し、調査をしたいと思います。
私はPythonのプログラミングができます。Twitter APIを実行するためのPythonスクリプトを書くつもりです。</font>)

・`Hi,team.`を文章の先頭に付与しておいて、フレンドリー感を少し演出(違
・仕事で英語での問い合わせメールの文章をいろいろ見てると、「`Dear...`」と書く人もいるが、「`Hi!`」とか「`Hi,team.`」と挨拶もそこそこに、いきなり要件書く人もそれなりにいるので真似てみた。
・日本人のメールの文章は正直長すぎやねん。プログラムのコマンドを書きつらねるようなイメージで英文を生成するとよろしいかと。
・文章の書き方として、まず自分が何者かを述べた上で、`I'd like to...`のイディオムを用いて、TwitterAPIを使いたい旨を書いて、`because of`とか使ってなぜ使いたいのか？Why？をつらつら加筆する感じで文章を長くしていくと、それらしい200文字以上の文章が出来上がるのではないかと。(← いや知らんけど。Google翻訳でそれっぽい文章をイミテートした。)
・申請した後に少し後悔したのは、リーナス・トーバルズ氏の「**ワタシハ、リナックス、チョットデキル**」的なニュアンスで、自分はpythonプログラミングができると書いた文章で、「`a little`」とかを付ければ良かったかナア？と思ったけど（すんなり申請通たのであれ）。自分で言うほどPythonエキスパートではないので、慎みが足りなかったデス。反省。

######Q2)どのようにTwitterデータを分析するかを説明 (※100文字以上)
>例）Execute Twitter API in python, collect tweeted records about our products, 
and store data in our relational database via Pandas. The text data is then analyzed.
(<font color=blue>TwitterAPIをPythonで実行して、自社製品についてのツイートを収集します。
そして自社のリレーショナルデータベース(RDB)にPandasを使ってデータを保存します。その上で、テキストデータを分析します。</font>)

・明記点は3点、[1]PythonでAPIを実行すること、[2]自社製品についてのツイートをAPIを使って収集すること、[3]PandasでRDBにデータを保存すること(そして収集データでテキスト分析すること)
・ Pandasが何かはおそらくTwitterの該当チームの人間なら知っていると思うが、もし不安ならば、`Pansas ,which is a software library written for the Python programming language for data manipulation and analysis....`みたいな説明文言を併記しておくとより文章が充実して先方に伝わりやすかったかもしれないですね(←申請通ったので多分上記でもOK)。

######その他の留意点
・twitterアカウントは、連絡先電話番号とメールアドレスを登録する。
・電話番号は登録後に、Verifyチェックで、サービスショートメールでverify番号が届くので番号を登録すれば処理完了。
・利用目的の文章と、分析有無はYesなので、上記のように英文を頑張って記述する。
・ツイート、リツイート等は今回はしない(検索収集用途な)ので、今回はNOを選択。
・Twitterデータの外部公開有無は、今回は公開しないので、NOを選択。
・政府機関で利用するしないは、今回は利用しないので、NOを選択。
・APply画面でSubmitすると、確認メールが登録したメールアドレスに届くので、「Confirm your email」をクリックして、画面で登録する。
・自分の場合、対して追加登録することもなく、１日くらいで登録認可された模様。

##Twitter APIをPythonで利用する

```python:twitter.py
import tweepy
import datetime
import pandas as pd
import sqlalchemy
from sqlalchemy import create_engine

# DB接続設定文字列
CONNECT_INFO = 'mssql+pyodbc://hogehoge'   #hogehoge＝ODBC名
engine = sqlalchemy.create_engine(CONNECT_INFO, encoding='utf-8')


def gettwitterdata(keyword):

    #Twitter APIを使用するためのConsumerキー、アクセストークン設定
    Consumer_key = 'hoge...hoge'
    Consumer_secret = 'fuga...fuga'
    Access_token = 'foo...foo'
    Access_secret = 'baa...baa'

    #認証
    auth = tweepy.OAuthHandler(Consumer_key, Consumer_secret)
    auth.set_access_token(Access_token, Access_secret)

    api = tweepy.API(auth, wait_on_rate_limit = True)

    #検索キーワード設定 
    q = keyword

    #つぶやきを格納するリスト
    tw0,tw1,tw2,tw3,tw4 =[],[],[],[],[]
    tw5,tw6,tw7,tw8,tw9 =[],[],[],[],[]
    twX = []
    
    #Reference
    #https://developer.twitter.com/en/docs/tweets/search/api-reference/get-search-tweets

    #カーソルを使用してデータ取得
    for tweet in tweepy.Cursor(api.search, q=q, count=100,tweet_mode='extended').items():

        #つぶやき時間がUTCのため、JSTに変換
        jsttime = tweet.created_at + datetime.timedelta(hours=9)
        #print(jsttime)
        tw0.append(tweet.id )
        tw1.append(tweet.full_text)
        tw2.append(tweet.created_at)
        tw3.append( jsttime )
        tw4.append(tweet.user.screen_name)
        tw5.append(tweet.user.name)
        tw6.append(tweet.user.id)
        tw7.append(tweet.user.description)
        tw8.append(tweet.user.friends_count)
        tw9.append(tweet.user.followers_count)
        twX.append(1)　#検索文字列を後でDB上でID識別するため

        #tw11.append(tweet.favorite_count)
        #tw12.append(tweet.retweet_count)

        
        #つぶやきテキスト(FULL)を取得
        #print(tweet.full_text + '\n')
    
    df = pd.DataFrame(data={'rid': tw0,'txt': tw1,'gmt_tm': tw2 ,'jst_tm': tw3
                            ,'scnm': tw4,'nm': tw5,'uid': tw6,'dscptn': tw7,'frd_cnt': tw8,'flw_cnt': tw9,'fldid': twX})
    mp=100
    cnt= len(df.index)
    #print(cnt)
    if cnt>1 :lpend = round(cnt/mp)
    lpend= lpend+1    
    print(lpend)
    
    for i in range(lpend):
        st=i*mp
        ed =st+mp-1
        print(st,ed)
        df_sub = df[st: ed]
        #display( df_sub )
        df_sub.to_sql("tblTWtemp", engine ,schema='dbo', index= False , if_exists='append' )
        print(i)
        
if __name__ == '__main__':

    #検索キーワードを入力  ※リツイートを除外する場合 「キーワード -RT 」と入力
    keyword ='シャープ -RT'
    print(keyword)
    gettwitterdata(keyword)

```
・TwitterAPIを使用するには、Consumerキー、アクセストークンなどが必要。TwitterAPI申請する際に参照したDevelopersページで、申請が通過した後にConsumerキー、アクセストークンなどをWebで参照して、API実行時に指定するべし。
・上記pythonスクリプトの処理の流れとしては、TwitterAPIの申請時に英文で記述した通り、[1]PythonでTwitterAPIを実行する、[2]API実行結果をPandasのデータフレームオブジェクト生成する、[3]Pandasのto_sql()を使って、最寄りのリレーショナルデータベース(RDB、上記ではMSSQL)の任意のテーブルにデータを保存する、の３工程で処理を行う。
・Pythonのライブラリに「<font color=blue>**tweepy**</font>」というtwitterAPIを実行するためのライブラリが用意されているので、それを利用する。　https://tweepy.readthedocs.io/en/latest/
・検索キーワードは、「<font color=red>ーRT</font>」をつけてあげると、リツイート文は除外して検索できる。
・Twitter Search API(Standard)だと、Twitter上の７日分の任意の文字列を検索可能。
・APIは15分に180回までの実行上限が設けられている
・TwitterAPIを実行する引数のcount=100は、twitterのページ数を表す。なお１ページは15ツイート相当。
・Pandasのデータフレームオブジェクトは、行ごとにAppend()して追加するのではなく、列ごとにリストを用意してリストに追記した上で、リスト群を束ねてPansasのデータフレームを生成した方がパフォーマンスがよいらしい。

・ツイート内容は、`tweet.full_text`で取得可能。
・ツイートのつぶやき時間(`tweet.created_at`)がUTC時間で保持されているので、JST（日本時間）に変換した列も生成しておく。
・JST時間は、UTC時間から9時間加算すると生成可能(＝日本とグリニッジ天文台との時差は＋9時間。`datetime.timedelta()`を使う）
・PandasのデータフレームをRDBに保存する場合は、Pandasの`to_sql()`を使ってテーブルに保存する
・最初まとめてデータフレームのデータをそのままRDBに保存しようとしたのだが、MSSQLのエラーを吐いたので、上記では、データフレームを100レコードずつ抽出して保存する処理をforループで繰り返している。そのために最初にデータフレームのレコード保持数を`len()`で取得して、100で割って何回繰り返し処理をするべきかを計算している。
・上記では、誰が何をツイートしたかを知りたいので、ユーザー情報として、`user.id`の他に、`screen_name`と`name`、`description`、`friends_count`、`followers_count`を合わせて取得している。
・そのツイートに対するリツイート数(`retweet_count`)とお気に入り数(`favorite_count`)は今回は取得しないことにした。上記のスクリプトをWindowsOSのタスクスケジューラーで10分に１回とか30分に1回とか1時間に1回などの間隔で定期実行するような運用にすると、ツイート直後のそれほど「お気に入り」や「リツイート」がつかない状態のツイートを検索してDBに格納するので、取得してもあまり意味がないのかなという観点で今回は見送り。
・検索文字列で、例えば自分の担当する自社製品の製品名などを記して、定点観測すればマーケティングの何かの参考情報として収集できるのではないかと思われ。
・上記スクリプトでは、株式会社シャープのSNSソーシャルマーケティング担当者がTwitterで「シャープ(製品)」についてエゴサーチ？する的なシチュエーションで検索文字列を「シャープ」を指定するケースを想定して、検索文字列に「シャープ」と記述したが、Twitter見てると「シャープ」の他に「Sharp」も検索文字列に設定した方が良さそうだというのが１点、また逆に「シャープペンシル」(文房具)や「シャープレシオ」(金融用語)などの株式会社シャープとは関係なさそうなワードは除外した方がいいのかもという点が留意点として挙げられる。

・APIリファレンス↓
https://developer.twitter.com/en/docs/tweets/search/api-reference/get-search-tweets

## Appendix：数年前にRubyで書いたスクリプト(備忘メモ)
```ruby:twitter.rb
#! ruby -Ks
#!/usr/bin/ruby

require 'twitter'
require 'nkf'
require 'yaml'
require 'rubygems'
require 'active_record'

#APIやDBを触るためのKEYをyaml_fileから取得
data = YAML.load_file("/tw/hoge.yml")

#set API_KEY
TW_CONSUMER_KEY = data["ck"]
TW_CONSUMER_SECRET = data["cs"]
TW_ACCESS_TOKEN = data["at"]
TW_ACCESS_TOKEN_SECRET = data["as"]

#Connect database
ActiveRecord::Base.establish_connection(
	:adapter => data["adpt"],
	:database => data["db"]
)

# DB_model
class Twtbl < ActiveRecord::Base
  def to_s
    return  "#{id}@#{time}: #{text}"
  end
end

#日時取得
day = Array.new(3)
day[0] = Time.now
day[1] = day[0].strftime("%Y%m%d_%H%M%S")

# twitterログイン
twClient = Twitter::REST::Client.new do |config|
	config.consumer_key = TW_CONSUMER_KEY
	config.consumer_secret = TW_CONSUMER_SECRET
	config.access_token = TW_ACCESS_TOKEN
	config.access_token_secret = TW_ACCESS_TOKEN_SECRET
end
 
for k in 1..2
	# 検索ワードの設定
	if k == 1 
		word = NKF.nkf("-Sw","タニタ") 
	elsif k == ２
		word = "Sharp OR " + NKF.nkf("-Sw","シャープ")
	else
	end 

	# word を含む tweet を 100 件取得する
	results = twClient.search(word, :count => 100, :result_type => "recent")
 
	results.attrs[:statuses].each do |tweet|
		tm_obj= DateTime.parse(tweet[:created_at])
		tm = tm_obj.new_offset( Rational(3,8) ).to_s		
		tm_gmt= tm_obj.to_s
		id = tweet[:id].to_s
		uid = tweet[:user][:id].to_s
		usr = tweet[:user][:screen_name].to_s
		lct = tweet[:user][:location].to_s
		dsp = tweet[:user][:description].to_s
		fwrc = tweet[:user][:followers_count].to_s
		ferc = tweet[:user][:friends_count].to_s
		tx0 = tweet[:text].to_s
		tx1 = tx0.gsub("¥n"," ")

	#p tweet[:user]

		Twtbl.create(
	              :createdtime => tm,
	              :twid => id,
                  :uid => uid,
	              :usr => usr,
	              :location => lct,
	              :description => dsp,  
		          :flwcnt => fwrc,
	              :frdcnt => ferc,
		          :txt => tx1,
		          :fno => day[1],
	              #:InsertTime => Time.now,
	              :created_GMTtime =>tm_gmt,
		          :inv => 0 
		)
	end

	p 'finish'
end
```
　数年前にRubyでTwitterAPIを実行するスクリプトを記述したが、備忘メモとして記しておく。処理の流れは、上記PythonでPandasでto_SQL()でRDBに保存するスクリプトとほぼ変わらずで、Rubyの場合、Ruby on RailsのMVCモデルのMの部分(Model)のO/Rマッパーライブラリ「ActiveRecord」を使って、RDBに保存している。