LoginSignup
12
10

More than 3 years have passed since last update.

Twitter API 検索で大量データを収集(CSV)

Posted at

開発環境

 Python3.7.3
 Twitter API

参考にしたページ

https://qiita.com/kngsym2018/items/2524d21455aac111cdee
http://westplain.sakuraweb.com/translate/twitter/Documentation/REST-APIs/Public-API/The-Search-API.cgi
https://syncer.jp/Web/API/Twitter/REST_API/
https://qiita.com/mida12251141/items/97bce06e4167db8ed3d5
https://qiita.com/tomozo6/items/d7fac0f942f3c4c66daf

事前にやっておくこと

Twitter APIの登録申請。ここでは割愛。
私は申請から許可まで4日ほどかかりました。
「参考にしたページ」の一番目で丁寧な解説がされてます。

やりたいこと

1レコード1ツイートなテーブル形式の状態でcsvファイルに保存する。
各データには改行はない。
なるべく大量にデータを取得する。

困ったこと

・一度に検索できるツイート数の上限は100ツイート
・上項の処理の連続実行上限は180回(上限までいくと15分間の待機が必要)
・検索できるツイートデータは一週間前まで
・下記5項目はカンマやら改行やらの楽園状態なので文字列処理必須

・Name
・Screen Name
・Text
・Description
・Location

※Locationは適当なこと書いてるユーザが多すぎてデータとして使えない

取得したツイートデータを変数csvlinetextに入れた後の文字列整形を下記のように行った。
他にもいい方法あると思うけど手っ取り早くこれで対処した。

twitterapi.py
            #textの文字列を整形
            csvlinetext = line["text"].strip()            #ツイートデータから改行を削除
            csvlinetext = csvlinetext.replace(",", " ")   #カンマ文字を半角スペースに置換
            csvlines = csvlinetext.splitlines()           #配列変数に格納することで消しきれない改行を削除
            csvlinetext = ''.join(csvlines)               #配列変数の全要素内のデータを結合

シナリオ

分かってる人は見なくてもいいやつ。
この流れでコードを組み立てれば上手くいく。

01.Twitter API登録時にもらう認証キーを変数に代入する
02.検索ワードを変数に代入する
03.検索プロパティを配列変数に代入する
04.OAuth認証でセッションを確立する
(ループ処理開始)
05.Twitter API利用制限回数のチェック
06.セッション切断
07.06の制限にかかった場合は15分待機
08.変数maxidを検索プロパティに指定
09.OAuth認証でセッションを確立する
10.検索実行して結果を変数csvline1に代入する
11.変数の結果をCSVに書き込む
12.ツイートIDを変数maxidに代入する
(ループ処理終了)

ソース

python
import os
import json
import config
import csv
import time
import math
from requests_oauthlib import OAuth1Session
from pytz import timezone
from dateutil import parser
from dateutil.relativedelta import relativedelta
from datetime import datetime, date, timedelta
import json, time, pytz, re, sys,traceback

#認証キーの変数代入とセッション確立
CONSUMER_KEY = "XXXXXXXXXXXXXXXXXXX"
CONSUMER_SECRE = "XXXXXXXXXXXXXXXXXXX"
ACCESS_TOKEN = "XXXXXXXXXXXXXXXXXXX"
ACCESS_SECRET = "XXXXXXXXXXXXXXXXXXX"

#+****************************************************************
#関数処理
#+****************************************************************

#セッション確立
def getTwitterSession():
    return OAuth1Session(CONSUMER_KEY, CONSUMER_SECRE, ACCESS_TOKEN, ACCESS_SECRET)

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

#API利用制限ステータスチェック
def rate_limit_status():
    limit = 0
    remaining = 0
    reset_minute = 0
    twitter = OAuth1Session(CONSUMER_KEY, CONSUMER_SECRE, ACCESS_TOKEN, ACCESS_SECRET)
    url = "https://api.twitter.com/1.1/application/rate_limit_status.json"
    req = twitter.get(url)
    if req.status_code == 200:
        res = json.loads(req.text)
        limit = res['resources']['search']['/search/tweets']['limit']
        remaining = res['resources']['search']['/search/tweets']['remaining']
        reset = res['resources']['search']['/search/tweets']['reset']
        reset_minute = math.ceil((reset - time.mktime(datetime.now().timetuple())) / 60)
    twitter.close()
    return limit, remaining, reset_minute

#検索条件を配列変数に代入
def getParam():
    params ={
            'count'         : 100,
            'q'             : keyword,
            'result_type'   : 'mixed',
            'max_id'        : maxid
            }
    twitter = getTwitterSession()
    req = twitter.get(url, params = params)
    return twitter, params, req

#+****************************************************************
#メイン処理
#+****************************************************************

#Twitter Endpoint
url = 'https://api.twitter.com/1.1/search/tweets.json'

#ツイートID
maxid = ''
#検索ワード
keyword = '英会話'
#実行日の取得(csvファイル命名用)
today = date.today()

#ツイート取得開始日
start_dt = today
#start_dt = datetime.strptime(start_dt, '%Y%m%d')
dt1 = (start_dt).strftime('%Y-%m-%d')

#ツイート取得最終日
end_dt  = (start_dt - timedelta(days=7))
dt2 = (end_dt).strftime('%Y-%m-%d')

since = str(dt1) + '_00:00:00_JST'
until = str(dt2) + '_23:59:59_JST'

csvline1 = "DateTime,ID,User ID,Name,Screen Name,Text,Follower Count,Friend Count,Favorite Count,Retweet Count,Description,Location\n"
with open("twitter_data_%s_%s.csv" % (keyword,today), "a") as f:
    f.write(csvline1)

for i1 in range(5000):
    #API使用制限回数チェック
    limit, remaining, reset_minute = rate_limit_status()
    print(remaining)
    #API使用制限解除待機
    if remaining == 0:
        print("** Waiting for limit release **")
        time.sleep(60 * (int(reset_minute) + 1))
        time.sleep(1)
    twitter, params, req = getParam()
    if req.status_code == 200:
        res = json.loads(req.text)
        i2 = 0
        i3 = 0
        for line in res['statuses']:
            i3 += 1
            if i3 <= 3:
                continue
            t = str_to_date_jp(line["created_at"])
            maxid = line['id']
            maxid -= 1
            #Nameの文字列を整形
            csvlinename = line["user"]["name"].strip()
            csvlinename = csvlinename.replace(",", " ")
            csvlines = csvlinename.splitlines()
            csvlinename = ''.join(csvlines)
            #Screen Nameの文字列を整形
            csvlinescreen_name = line["user"]["screen_name"].strip()
            csvlinescreen_name = csvlinescreen_name.replace(",", " ")
            csvlines = csvlinescreen_name.splitlines()
            csvlinescreen_name = ''.join(csvlines)
            #textの文字列を整形
            csvlinetext = line["text"].strip()
            csvlinetext = csvlinetext.replace(",", " ")
            csvlines = csvlinetext.splitlines()
            csvlinetext = ''.join(csvlines)
            #descriptionの文字列を整形
            csvlinedescription = line["user"]["description"].replace(",", " ")
            csvlinedescription = csvlinedescription.strip()
            csvlines = csvlinedescription.splitlines()
            csvlinedescription = ''.join(csvlines)
            #locationの文字列を整形
            csvlinelocation = line["user"]["location"].replace(",", " ")
            csvlinelocation = csvlinelocation.strip()
            csvlines = csvlinelocation.splitlines()
            csvlinelocation = ''.join(csvlines)
            csvline1 = "%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s" % (t,line["id"],line["user"]["id"],csvlinename,csvlinescreen_name,csvlinetext,line["user"]["followers_count"],line["user"]["friends_count"],line["favorite_count"],line["retweet_count"],csvlinedescription,csvlinelocation)
            #末尾に改行を追加
            csvline1 = format(csvline1) + '\n'
            with open("twitter_data_%s_%s.csv" % (keyword,today), "a") as f:
                f.write(csvline1)
            i2 += 1
    else:
        print("Failed: %d" % req.status_code)
f.close()
print(maxid)
print("** Finished **")

収集したデータを分析する

Mecabを使って単語と品詞のみを抽出すると
再頻出ワードの件数やツイートの傾向が分かる。
マーケティング施策の参考情報程度にはなると思いますが、
複数ワードで検索したデータをマージするなどの設計をしないと
有用性の高い分析はできなそう。

twitterapi.py
import csv
import pandas as pd
import MeCab

mecab = MeCab.Tagger ('-d /usr/local/lib/mecab/dic/mecab-ipadic-neologd')

i = 1
f = open('/Users/nomotom/Workspace/py/xxxxxxxx.csv', 'r')
reader = csv.reader(f)
line = f.readline()
for row in reader:
    text = row[5]
    mecab.parse('')
    node = mecab.parseToNode(text)
    while node:
        #単語を取得
        word = node.surface
        #品詞を取得
        pos = node.feature.split(",")[1]
        line = word + ',' + pos + ',\n'
        with open("mecab_data.csv", "a") as f:
            f.write(line)
            print(i)
            i += 1
        node = node.next

f.close()
12
10
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
10